|
1 /* |
|
2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Uses XML parser to read the manifest and created objects that |
|
15 * represent the manifest. |
|
16 * |
|
17 */ |
|
18 |
|
19 package com.nokia.tools.themeinstaller.installationmanager; |
|
20 |
|
21 import java.io.File; |
|
22 import java.io.IOException; |
|
23 import java.util.Enumeration; |
|
24 import java.util.Vector; |
|
25 |
|
26 import org.w3c.dom.Document; |
|
27 import org.w3c.dom.NamedNodeMap; |
|
28 import org.w3c.dom.Node; |
|
29 import org.w3c.dom.NodeList; |
|
30 |
|
31 import com.nokia.tools.themeinstaller.localisation.DTDReader; |
|
32 import com.nokia.tools.themeinstaller.localisation.Localisation; |
|
33 import com.nokia.tools.themeinstaller.localisation.LocalisationStore; |
|
34 import com.nokia.tools.themeinstaller.odtconverter.ConverterProperties; |
|
35 import com.nokia.tools.themeinstaller.odtconverter.IParseOperationListener; |
|
36 import com.nokia.tools.themeinstaller.odtconverter.MimeTypeResolver; |
|
37 import com.nokia.tools.themeinstaller.odtconverter.ThemeStatusResolver; |
|
38 import com.nokia.tools.themeinstaller.xmlparser.XMLParser; |
|
39 |
|
40 /** |
|
41 * Uses XML parser to read the manifest and created objects that represent the |
|
42 * manifest. |
|
43 */ |
|
44 public class ManifestFactory implements IParseOperationListener { |
|
45 |
|
46 // CONSTANTS |
|
47 // Manifest root node names |
|
48 private static final String MULTI_THEME = "datfiles"; |
|
49 |
|
50 // Manifest element names |
|
51 private static final String APP_UID_ELEMENT = "AppUid"; |
|
52 private static final String PROVIDER_UID_ELEMENT = "Provideruid"; |
|
53 private static final String THEME_UID_ELEMENT = "ThemeUid"; |
|
54 private static final String THEME_STATUS_ELEMENT = "ThemeStatus"; |
|
55 private static final String THEME_FULL_NAME_ELEMENT = "ThemeFullName"; |
|
56 private static final String THEME_SHORT_NAME_ELEMENT = "ThemeShortName"; |
|
57 private static final String THEME_VERSION_ELEMENT = "ThemeVersion"; |
|
58 private static final String FILE_XML_ELEMENT = "FileXML"; |
|
59 private static final String FILE_CSS_ELEMENT = "FileCSS"; |
|
60 private static final String FILE_DTD_ELEMENT = "FileDTD"; |
|
61 private static final String FILE_DAT_ELEMENT = "FileDAT"; |
|
62 private static final String FILE_RESOURCE_ELEMENT = "FileResource"; |
|
63 private static final String CACHE_VALUE_MEMORY = "CacheMemory"; |
|
64 private static final String LOCKING_ELEMENT = "Locking"; |
|
65 private static final String LOCKED_VALUE = "Locked"; |
|
66 private static final String CACHE_TYPE_ELEMENT = "CacheType"; |
|
67 private static final String CACHE_VALUE_NONE = "CacheNone"; |
|
68 private static final String CACHE_VALUE_FILE = "CacheFile"; |
|
69 |
|
70 // Language element names |
|
71 private static final String LANGUAGE_SPECIFIC_ELEMENT = "LanguageSpecific"; |
|
72 private static final int LANGUAGE_INDEPENDENT = 0; |
|
73 private static final int LANG_NOT_SET = -1; |
|
74 |
|
75 // Integer conversion radix |
|
76 private static final int RADIX = 16; |
|
77 |
|
78 // Screen size |
|
79 private static final int SCREEN_SIZE_X = 0; |
|
80 private static final int SCREEN_SIZE_Y = 0; |
|
81 |
|
82 // Resource file cache type |
|
83 public static int CACHE_TYPE_CACHE_NONE = 0; |
|
84 public static int CACHE_TYPE_CACHE_FILE = 1; |
|
85 public static int CACHE_TYPE_CACHE_MEMORY = 2; |
|
86 |
|
87 // Locking policy flag-definition from native, bit-masked. |
|
88 public static final int E_XN_UNLOCKED = 0x0000; // 0b0000000000000000, |
|
89 public static final int E_XN_LOCKED = 0x0001; // 0b0000000000000001, |
|
90 |
|
91 public static final String CURRENT_DIR = "."; |
|
92 |
|
93 // Property keys |
|
94 private static final String THEME_PROVIDER_KEY = "theme_provider_name"; |
|
95 private static final String NAME_SPACE_KEY = "theme_name_space"; |
|
96 |
|
97 // Lock for monitoring parse operation completions |
|
98 private Lock iLock; |
|
99 |
|
100 // Mime type resolver |
|
101 private MimeTypeResolver iMimeTypeResolver; |
|
102 |
|
103 // Converter properties |
|
104 private ConverterProperties iProperties; |
|
105 |
|
106 // Localisation settings |
|
107 private File iLocSettings; |
|
108 |
|
109 /** |
|
110 * Constructor. |
|
111 * |
|
112 * @param aLocSettings |
|
113 * Localisation settings |
|
114 * @throws IOException |
|
115 * if converter properties can not be read |
|
116 */ |
|
117 public ManifestFactory(File aLocSettings) throws IOException { |
|
118 iLock = new Lock(); |
|
119 iMimeTypeResolver = new MimeTypeResolver(); |
|
120 iProperties = ConverterProperties.getInstance(); |
|
121 iLocSettings = aLocSettings; |
|
122 } |
|
123 |
|
124 /** |
|
125 * Parse a manifest and create the manifest object. |
|
126 * |
|
127 * @param aFile |
|
128 * Manifest file |
|
129 * @return Manifest instance |
|
130 * @throws IOException |
|
131 * if the manifest can not be read |
|
132 */ |
|
133 public IThemeManifest createManifest(File aFile) throws IOException { |
|
134 // Read the manifest to the DOM document |
|
135 Document document = readManifest(aFile); |
|
136 IThemeManifest manifest = new ThemeManifest(); |
|
137 |
|
138 // Set data directory that contains the data files of the theme |
|
139 if (aFile.getParent() == null) { |
|
140 manifest.setDataDir(CURRENT_DIR + File.separatorChar); |
|
141 } else { |
|
142 manifest.setDataDir(aFile.getParent() + File.separatorChar); |
|
143 } |
|
144 |
|
145 // Parse manifest contents |
|
146 String rootNodeName = document.getFirstChild().getNodeName(); |
|
147 if (rootNodeName == MULTI_THEME) { |
|
148 // Multi theme manifest |
|
149 parseMultiThemeManifest(document, manifest); |
|
150 } else { |
|
151 // Single theme manifest |
|
152 parseManifest(document, manifest); |
|
153 parseLanguageSpecificData(document, manifest); |
|
154 parseResources(document, manifest, LANGUAGE_INDEPENDENT); |
|
155 } |
|
156 |
|
157 return manifest; |
|
158 } |
|
159 |
|
160 /* |
|
161 * (non-Javadoc) |
|
162 * |
|
163 * @seecom.nokia.tools.themeinstaller.odtconverter.IParseOperationListener# |
|
164 * parseOperationCompleted(int, java.lang.String) |
|
165 */ |
|
166 public void parseOperationCompleted(int aErr, String aReason) { |
|
167 iLock.unLock(); |
|
168 if (aErr != 0) { |
|
169 throw new IllegalArgumentException( |
|
170 "Theme manifest parsing failed: " + aErr + ", " + aReason); |
|
171 } |
|
172 } |
|
173 |
|
174 /** |
|
175 * Parse the manifest file. |
|
176 * |
|
177 * @param aManifest |
|
178 * Manifest file |
|
179 * @return DOM Document of the manifest |
|
180 */ |
|
181 private Document readManifest(File aManifest) { |
|
182 // Parse the manifest |
|
183 XMLParser parser = new XMLParser(aManifest.getPath()); |
|
184 parser.addListener(this); |
|
185 |
|
186 try { |
|
187 parser.parse(); |
|
188 } catch (Exception e) { |
|
189 throw new IllegalArgumentException( |
|
190 "Theme manifest parsing failed: " + e.getMessage()); |
|
191 } |
|
192 |
|
193 // Wait for the operation completion |
|
194 iLock.lock(); |
|
195 |
|
196 // Return the document that was formed |
|
197 return parser.getDOMDocument(); |
|
198 } |
|
199 |
|
200 /** |
|
201 * Parses a multi theme manifest from DOM to the manifest instance. |
|
202 * |
|
203 * @param aDocument |
|
204 * DOM Document containing the manifest data (source) |
|
205 * @param aManifest |
|
206 * Theme manifest (destination) |
|
207 */ |
|
208 private void parseMultiThemeManifest(Document aDocument, |
|
209 IThemeManifest aManifest) { |
|
210 // Add DAT file names |
|
211 NodeList nodes = aDocument.getElementsByTagName(FILE_DAT_ELEMENT); |
|
212 Node node = null; |
|
213 for (int i = 0; i < nodes.getLength(); i++) { |
|
214 node = nodes.item(i); |
|
215 aManifest.addManifestFile(aManifest.getDataDir() |
|
216 + node.getTextContent()); |
|
217 } |
|
218 } |
|
219 |
|
220 /** |
|
221 * Parses a manifest from DOM to the manifest instance. |
|
222 * |
|
223 * @param aDocument |
|
224 * DOM Document containing the manifest data (source) |
|
225 * @param aManifest |
|
226 * Theme manifest (destination) |
|
227 */ |
|
228 private void parseManifest(Document aDocument, IThemeManifest aManifest) { |
|
229 // Set application uid |
|
230 NodeList nodes = aDocument.getElementsByTagName(APP_UID_ELEMENT); |
|
231 Node node = checkOneNode(nodes, APP_UID_ELEMENT); |
|
232 if (node != null) |
|
233 aManifest.setApplicationUid(Long.valueOf(node.getTextContent(), |
|
234 RADIX)); |
|
235 |
|
236 // Set provider uid |
|
237 nodes = aDocument.getElementsByTagName(PROVIDER_UID_ELEMENT); |
|
238 node = checkOneNode(nodes, PROVIDER_UID_ELEMENT); |
|
239 if (node != null) |
|
240 aManifest |
|
241 .setProviderUid(Long.valueOf(node.getTextContent(), RADIX)); |
|
242 |
|
243 // Set theme uid |
|
244 nodes = aDocument.getElementsByTagName(THEME_UID_ELEMENT); |
|
245 node = checkOneNode(nodes, THEME_UID_ELEMENT); |
|
246 if (node != null) |
|
247 aManifest.setThemeUid(Long.valueOf(node.getTextContent(), RADIX)); |
|
248 |
|
249 // Set name space |
|
250 aManifest.setNameSpace(iProperties.getProperty(NAME_SPACE_KEY)); |
|
251 |
|
252 // Set theme provider name |
|
253 aManifest.setProviderName(iProperties.getProperty(THEME_PROVIDER_KEY)); |
|
254 |
|
255 // Set default theme full name before localization |
|
256 nodes = aDocument.getElementsByTagName(THEME_FULL_NAME_ELEMENT); |
|
257 if (nodes.getLength() > 0) { |
|
258 // Get first theme name that is found (for a default name). |
|
259 // The used name is specified in the language specific data. |
|
260 aManifest.setThemeFullName(nodes.item(0).getTextContent()); |
|
261 } |
|
262 // else |
|
263 // { |
|
264 // throw new IllegalArgumentException( |
|
265 // "Syntax error in manifest file: theme full name not found" ); |
|
266 // } |
|
267 |
|
268 // Set theme short name |
|
269 nodes = aDocument.getElementsByTagName(THEME_SHORT_NAME_ELEMENT); |
|
270 node = checkOneNode(nodes, THEME_SHORT_NAME_ELEMENT); |
|
271 if (node != null) |
|
272 aManifest.setThemeShortName(node.getTextContent()); |
|
273 |
|
274 // Set theme version |
|
275 nodes = aDocument.getElementsByTagName(THEME_VERSION_ELEMENT); |
|
276 node = checkOneNode(nodes, THEME_VERSION_ELEMENT); |
|
277 if (node != null) |
|
278 aManifest.setThemeVersion(node.getTextContent()); |
|
279 |
|
280 // Screen size, not used in Xuikon at the moment |
|
281 aManifest.setScreenSizeX(new Integer(SCREEN_SIZE_X)); |
|
282 aManifest.setScreenSizeY(new Integer(SCREEN_SIZE_Y)); |
|
283 |
|
284 // Resolve theme status |
|
285 nodes = aDocument.getElementsByTagName(THEME_STATUS_ELEMENT); |
|
286 int flags = ThemeStatusResolver.E_XN_THEME_STATUS_NONE; |
|
287 for (int i = 0; i < nodes.getLength(); i++) { |
|
288 node = nodes.item(i); |
|
289 flags |= ThemeStatusResolver.getValue(node.getTextContent()) |
|
290 .intValue(); |
|
291 if (node.getTextContent().equals( |
|
292 ThemeStatusResolver.THEME_STATUS_LICENCEE_RESTORABLE)) { |
|
293 // This theme is restored when licensee default theme is |
|
294 // restored. |
|
295 // When using this flag, the ThemeStatusLicenceeDefault-flag |
|
296 // must be activated. |
|
297 flags |= ThemeStatusResolver.E_XN_THEME_STATUS_LICENCEE_DEFAULT; |
|
298 } |
|
299 } |
|
300 aManifest.setThemeStatus(new Integer(flags)); |
|
301 |
|
302 // Set XML file name |
|
303 NodeList files = aDocument.getElementsByTagName(FILE_XML_ELEMENT); |
|
304 node = checkOneNode(files, FILE_XML_ELEMENT); |
|
305 if (node != null) |
|
306 aManifest.setXMLFile(node.getTextContent()); |
|
307 |
|
308 // Set CSS file name |
|
309 files = aDocument.getElementsByTagName(FILE_CSS_ELEMENT); |
|
310 node = checkMaxOneLanguageIndependentNode(files); |
|
311 if (node != null) { |
|
312 aManifest.setCSSFile(node.getTextContent()); |
|
313 } |
|
314 |
|
315 // Set DTD file name |
|
316 files = aDocument.getElementsByTagName(FILE_DTD_ELEMENT); |
|
317 node = checkMaxOneLanguageIndependentNode(files); |
|
318 if (node != null) { |
|
319 aManifest.setDTDFile(node.getTextContent()); |
|
320 } |
|
321 } |
|
322 |
|
323 /** |
|
324 * Parses language specific data in the manifest. |
|
325 * |
|
326 * @param aDocument |
|
327 * DOM Document containing the manifest data (source) |
|
328 * @param aManifest |
|
329 * Theme manifest (destination) |
|
330 * @throws IOException |
|
331 * if the manifest can not be parsed |
|
332 */ |
|
333 private void parseLanguageSpecificData(Document aDocument, |
|
334 IThemeManifest aManifest) throws IOException { |
|
335 // Get languages |
|
336 NodeList languages = aDocument |
|
337 .getElementsByTagName(LANGUAGE_SPECIFIC_ELEMENT); |
|
338 |
|
339 Node langSpecificNode = null; |
|
340 NamedNodeMap langAttr = null; |
|
341 NodeList langSpecificChildren = null; |
|
342 Node langSpecificChild = null; |
|
343 |
|
344 NodeList resources = aDocument |
|
345 .getElementsByTagName(FILE_RESOURCE_ELEMENT); |
|
346 Vector langResources = null; |
|
347 |
|
348 // Process all languages |
|
349 for (int i = 0; i < languages.getLength(); i++) { |
|
350 // Language specific data |
|
351 int langId = LANG_NOT_SET; |
|
352 String extDtd = null; |
|
353 String extCss = null; |
|
354 String themeFullName = null; |
|
355 |
|
356 // Take a LanguageSpecific node |
|
357 langSpecificNode = languages.item(i); |
|
358 |
|
359 // There should be only one language for each LanguageSpecific node |
|
360 langAttr = langSpecificNode.getAttributes(); |
|
361 if (langAttr.getLength() == 1) { |
|
362 String langStr = langAttr.item(0).getNodeValue(); |
|
363 langId = Integer.valueOf(langStr).intValue(); |
|
364 } |
|
365 |
|
366 langSpecificChildren = langSpecificNode.getChildNodes(); |
|
367 |
|
368 // Read language specific elements |
|
369 String nodeName = null; |
|
370 |
|
371 for (int j = 0; j < langSpecificChildren.getLength(); j++) { |
|
372 langSpecificChild = langSpecificChildren.item(j); |
|
373 nodeName = langSpecificChild.getNodeName(); |
|
374 |
|
375 // Language specific DTD file name |
|
376 if (FILE_DTD_ELEMENT.equals(nodeName)) { |
|
377 extDtd = langSpecificChild.getTextContent(); |
|
378 } |
|
379 // Language specific CSS |
|
380 else if (FILE_CSS_ELEMENT.equals(nodeName)) { |
|
381 extCss = langSpecificChild.getTextContent(); |
|
382 } |
|
383 // Localized theme full name |
|
384 else if (THEME_FULL_NAME_ELEMENT.equals(nodeName)) { |
|
385 themeFullName = langSpecificChild.getTextContent(); |
|
386 } |
|
387 } |
|
388 |
|
389 // Parse language specific resources |
|
390 langResources = parseResources(aManifest, resources, langId); |
|
391 |
|
392 // Verify that mandatory fields language id and DTD file were set |
|
393 if (langId == LANG_NOT_SET || extDtd == null) { |
|
394 throw new IllegalArgumentException( |
|
395 "Syntax error in language specifications of the manifest"); |
|
396 } |
|
397 |
|
398 // Find the DTD file for reading the localised theme full name |
|
399 File dtd = null; |
|
400 if (iLocSettings != null) { |
|
401 // Use enhanced localisation: Find the DTD file |
|
402 LocalisationStore ls = LocalisationStore |
|
403 .getInstance(iLocSettings); |
|
404 Localisation l = ls.getLocalisation(aManifest |
|
405 .getApplicationUid().longValue(), aManifest |
|
406 .getProviderUid().longValue(), aManifest.getThemeUid() |
|
407 .longValue()); |
|
408 dtd = l.findDTD(extDtd); |
|
409 } else { |
|
410 dtd = new File(aManifest.getDataDir() + extDtd); |
|
411 } |
|
412 |
|
413 // Resolve localised theme full name, if specified |
|
414 themeFullName = DTDReader.readEntity(dtd, themeFullName); |
|
415 |
|
416 // Create new language specific data and add it to the languages |
|
417 // list |
|
418 LanguageSpecificData language = new LanguageSpecificData( |
|
419 new Integer(langId), extDtd, extCss, themeFullName, |
|
420 langResources); |
|
421 aManifest.addLanguage(language); |
|
422 } |
|
423 |
|
424 // Unlocalized variant (causes the .o0000 file to be generated) |
|
425 LanguageSpecificData language = new LanguageSpecificData(new Integer( |
|
426 LANGUAGE_INDEPENDENT), null, null, null, null); |
|
427 aManifest.addLanguage(language); |
|
428 } |
|
429 |
|
430 /** |
|
431 * Parses resource data in the manifest. |
|
432 * |
|
433 * @param aDocument |
|
434 * DOM Document containing the manifest data (source) |
|
435 * @param aManifest |
|
436 * Theme manifest (destination) |
|
437 * @param aLanguageId |
|
438 * Id of the language of which resources will be parsed. On 0, |
|
439 * only language independent resources are parsed. |
|
440 */ |
|
441 private void parseResources(Document aDocument, IThemeManifest aManifest, |
|
442 int aLanguageId) { |
|
443 // Do the parsing operation |
|
444 NodeList resourceList = aDocument |
|
445 .getElementsByTagName(FILE_RESOURCE_ELEMENT); |
|
446 Vector resources = parseResources(aManifest, resourceList, aLanguageId); |
|
447 |
|
448 // Add resources to the manifest |
|
449 Enumeration e = resources.elements(); |
|
450 while (e.hasMoreElements()) { |
|
451 aManifest.addResource((ThemeResource) e.nextElement()); |
|
452 } |
|
453 } |
|
454 |
|
455 /** |
|
456 * Parses resource files defined in the manifest. Resources must be parsed |
|
457 * after the rest of the manifest is parsed. Theme status is used here for |
|
458 * determining locking policies. |
|
459 * |
|
460 * @param aManifest |
|
461 * Theme manifest |
|
462 * @param aNodeList |
|
463 * Node list to parse |
|
464 * @param aLanguageId |
|
465 * Id of the language of which resources will be parsed. On 0, |
|
466 * only language independent resources are parsed. |
|
467 */ |
|
468 private Vector parseResources(IThemeManifest aManifest, NodeList aNodeList, |
|
469 int aLanguageId) { |
|
470 Vector result = new Vector(); |
|
471 Node node = null; |
|
472 |
|
473 // Browse through all resources in the list |
|
474 int count = aNodeList.getLength(); |
|
475 for (int i = 0; i < count; i++) { |
|
476 node = aNodeList.item(i); |
|
477 String filename = node.getTextContent(); |
|
478 NamedNodeMap attributes = node.getAttributes(); |
|
479 |
|
480 int cacheType = CACHE_TYPE_CACHE_NONE; |
|
481 int lockingPolicy = E_XN_UNLOCKED; |
|
482 |
|
483 // Set cache type |
|
484 Node cacheTypeNode = attributes.getNamedItem(CACHE_TYPE_ELEMENT); |
|
485 if ((cacheTypeNode == null) |
|
486 || cacheTypeNode.getTextContent().equals(CACHE_VALUE_NONE)) { |
|
487 cacheType = CACHE_TYPE_CACHE_NONE; |
|
488 } else if (cacheTypeNode.getTextContent().equals(CACHE_VALUE_FILE)) { |
|
489 cacheType = CACHE_TYPE_CACHE_FILE; |
|
490 } else if (cacheTypeNode.getTextContent() |
|
491 .equals(CACHE_VALUE_MEMORY)) { |
|
492 cacheType = CACHE_TYPE_CACHE_MEMORY; |
|
493 } else { |
|
494 throw new IllegalArgumentException( |
|
495 "Syntax error in the manifest, can not resolve resource cache type"); |
|
496 } |
|
497 |
|
498 // Set locking policy |
|
499 Node locking = attributes.getNamedItem(LOCKING_ELEMENT); |
|
500 if (locking != null |
|
501 && locking.getTextContent().equals(LOCKED_VALUE)) { |
|
502 lockingPolicy = E_XN_LOCKED; |
|
503 } |
|
504 |
|
505 // If EXnThemeStatusLicenceeDefault flag is set, locking policy is |
|
506 // E_XN_LOCKED |
|
507 if ((aManifest.getThemeStatus().intValue() & ThemeStatusResolver.E_XN_THEME_STATUS_LICENCEE_DEFAULT) != 0) { |
|
508 lockingPolicy = E_XN_LOCKED; |
|
509 } |
|
510 |
|
511 // Resolve mime type |
|
512 String mime = iMimeTypeResolver.getMimeType(filename); |
|
513 |
|
514 // Resolve resource type |
|
515 int resourceType = iMimeTypeResolver.getResourceType(filename); |
|
516 |
|
517 // Verify language id |
|
518 Node parent = node.getParentNode(); |
|
519 NamedNodeMap attr = parent.getAttributes(); |
|
520 |
|
521 // Language specific resources |
|
522 if (attr.getLength() == 1 |
|
523 && aLanguageId == Integer.valueOf( |
|
524 attr.item(0).getNodeValue()).intValue()) { |
|
525 ThemeResource resource = new ThemeResource(filename, cacheType, |
|
526 lockingPolicy, aManifest.getNameSpace(), resourceType, |
|
527 mime); |
|
528 result.add(resource); |
|
529 } |
|
530 // Language independent resources |
|
531 else if (aLanguageId == LANGUAGE_INDEPENDENT |
|
532 && !LANGUAGE_SPECIFIC_ELEMENT.equals(parent.getNodeName())) { |
|
533 ThemeResource resource = new ThemeResource(filename, cacheType, |
|
534 lockingPolicy, aManifest.getNameSpace(), resourceType, |
|
535 mime); |
|
536 result.add(resource); |
|
537 } |
|
538 } |
|
539 |
|
540 return result; |
|
541 } |
|
542 |
|
543 /** |
|
544 * Checks that there exists just one node in the list |
|
545 * |
|
546 * @param aNodeList |
|
547 * Node list to be checked |
|
548 * @return Only one existing node |
|
549 * @throws IllegalArgumentException |
|
550 * If there is more or less than one node in list |
|
551 */ |
|
552 private Node checkOneNode(NodeList aNodeList, String tagName) { |
|
553 |
|
554 if (aNodeList.getLength() > 1) { |
|
555 throw new IllegalArgumentException( |
|
556 "Syntax error in manifest file, more child nodes than expected"); |
|
557 } |
|
558 return aNodeList.item(0); |
|
559 } |
|
560 |
|
561 /** |
|
562 * Checks that there exists max one node in the list and it is language |
|
563 * independent. |
|
564 * |
|
565 * @param aNodeList |
|
566 * Node list to be checked |
|
567 * @return The existing language independent node or null |
|
568 * @throws IllegalArgumentException |
|
569 * If there is more or less than one node in list |
|
570 */ |
|
571 private Node checkMaxOneLanguageIndependentNode(NodeList aNodeList) { |
|
572 Node result = null; |
|
573 int count = 0; |
|
574 for (int i = 0; i < aNodeList.getLength(); i++) { |
|
575 // Verify language in-dependency |
|
576 Node node = aNodeList.item(i); |
|
577 Node parent = node.getParentNode(); |
|
578 if (!LANGUAGE_SPECIFIC_ELEMENT.equals(parent.getNodeName())) { |
|
579 result = node; |
|
580 count++; |
|
581 } |
|
582 } |
|
583 |
|
584 if (count > 1) { |
|
585 throw new IllegalArgumentException( |
|
586 "Syntax error in manifest file, more language " |
|
587 + "independent child nodes than expected"); |
|
588 } |
|
589 |
|
590 return result; |
|
591 } |
|
592 |
|
593 } |