|
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: Starting point for theme install procedure. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 package com.nokia.tools.themeinstaller.installationmanager; |
|
20 |
|
21 import java.io.File; |
|
22 import java.io.FilenameFilter; |
|
23 import java.io.IOException; |
|
24 import java.io.InputStream; |
|
25 import java.util.Enumeration; |
|
26 import java.util.Observable; |
|
27 import java.util.Observer; |
|
28 import java.util.Vector; |
|
29 |
|
30 import javax.xml.transform.Result; |
|
31 import javax.xml.transform.Source; |
|
32 import javax.xml.transform.Transformer; |
|
33 import javax.xml.transform.TransformerFactory; |
|
34 import javax.xml.transform.dom.DOMSource; |
|
35 import javax.xml.transform.stream.StreamResult; |
|
36 |
|
37 import org.w3c.dom.Node; |
|
38 import org.w3c.dom.NodeList; |
|
39 import org.w3c.dom.traversal.NodeIterator; |
|
40 |
|
41 import com.nokia.tools.themeinstaller.defrep.DefinitionRepository; |
|
42 import com.nokia.tools.themeinstaller.defrep.IDefinitionRepository; |
|
43 import com.nokia.tools.themeinstaller.defrep.operations.FileOperation; |
|
44 import com.nokia.tools.themeinstaller.defrep.operations.FileOperationEvent; |
|
45 import com.nokia.tools.themeinstaller.odtconverter.ConverterProperties; |
|
46 import com.nokia.tools.themeinstaller.odtconverter.IParseOperationListener; |
|
47 import com.nokia.tools.themeinstaller.odtconverter.ODTDocument; |
|
48 import com.nokia.tools.themeinstaller.odtconverter.ODTHeader; |
|
49 import com.nokia.tools.themeinstaller.odtconverter.ODTInputStream; |
|
50 import com.sun.org.apache.xpath.internal.XPathAPI; |
|
51 |
|
52 /** |
|
53 * Installation Manager class is the starting point for the theme installation |
|
54 * procedure. |
|
55 */ |
|
56 public class InstallationManager implements Observer, IInstallationListener |
|
57 { |
|
58 |
|
59 protected static final String MANIFEST_SUFFIX = ".dat"; |
|
60 |
|
61 // Theme manifest file |
|
62 private File iManifest; |
|
63 |
|
64 // Destination root directory |
|
65 private File iDestinationDir; |
|
66 |
|
67 // Definition repository for file operations |
|
68 private IDefinitionRepository iDefRep; |
|
69 |
|
70 // Data directory containing the theme to install |
|
71 private String iDataDir; |
|
72 |
|
73 // Installation observer |
|
74 private IInstallationListener iListener; |
|
75 |
|
76 // Resource installer |
|
77 private IResourceInstaller iResourceInstaller; |
|
78 |
|
79 // Installation list of ongoing installations |
|
80 private InstallationList iList; |
|
81 |
|
82 // Lock for asynchronous operations. |
|
83 private Lock iLock; |
|
84 |
|
85 // Lock for multi theme installs |
|
86 private Lock iMultiThemeLock; |
|
87 |
|
88 // Localisation settings |
|
89 private File iLocSettings; |
|
90 |
|
91 //DTD may contain some errors such as missing semicolon. Set |
|
92 //this to true if these are to be fixed. Currently passed via |
|
93 //argument. |
|
94 private static boolean fixDTD = false; |
|
95 |
|
96 /** |
|
97 * Default constructor |
|
98 * @param aParams Installation parameters |
|
99 * @param aListener Installation observer |
|
100 * @throws IOException if Resource Installer can not be created |
|
101 */ |
|
102 public InstallationManager( InstallationParameters aParams, |
|
103 IInstallationListener aListener ) |
|
104 throws IOException |
|
105 { |
|
106 // Properties must be initialized before using them |
|
107 ConverterProperties.initialize( aParams.getPropFile() ); |
|
108 |
|
109 iManifest = aParams.getManifest(); |
|
110 iLocSettings = aParams.getLocSettings(); |
|
111 iDestinationDir = aParams.getDestinationDir(); |
|
112 iListener = aListener; |
|
113 |
|
114 // Create destination directory structure |
|
115 if( !iDestinationDir.exists() ) |
|
116 { |
|
117 iDestinationDir.mkdirs(); |
|
118 } |
|
119 |
|
120 iDefRep = DefinitionRepository.getInstance(); |
|
121 |
|
122 if( iManifest.getParent() == null ) |
|
123 { |
|
124 iDataDir = ManifestFactory.CURRENT_DIR + File.separatorChar; |
|
125 } |
|
126 else |
|
127 { |
|
128 iDataDir = iManifest.getParent() + File.separatorChar; |
|
129 } |
|
130 |
|
131 iResourceInstaller = |
|
132 new ResourceInstaller( iDefRep, iDestinationDir, iDataDir); |
|
133 iList = new InstallationList(); |
|
134 iLock = new Lock(); |
|
135 iMultiThemeLock = new Lock(); |
|
136 } |
|
137 |
|
138 |
|
139 public static boolean isFixDTD() { |
|
140 return fixDTD; |
|
141 } |
|
142 |
|
143 |
|
144 public static void setFixDTD(boolean fixDTD) { |
|
145 InstallationManager.fixDTD = fixDTD; |
|
146 } |
|
147 |
|
148 |
|
149 /** |
|
150 * Starts the actual installation |
|
151 * Progress will be informed via listener |
|
152 * @throws IOException If files cannot be found, or new files cannot be written |
|
153 * @throws IllegalArgumentException If there exists syntax errors in manifest file |
|
154 */ |
|
155 public void startInstallation() throws IOException |
|
156 { |
|
157 // Source parameter is a directory |
|
158 if( iManifest.isDirectory() ) |
|
159 { |
|
160 Enumeration manifests = searchManifests( iManifest ).elements(); |
|
161 if( manifests.hasMoreElements() ) |
|
162 { |
|
163 // Install all found themes |
|
164 installMultiTheme( manifests ); |
|
165 } |
|
166 else |
|
167 { |
|
168 // No themes found |
|
169 throw new IllegalArgumentException( |
|
170 "Manifest files not found from: " + iManifest.getPath() ); |
|
171 } |
|
172 } |
|
173 // Source parameter is a file |
|
174 else |
|
175 { |
|
176 // Parse the manifest |
|
177 ManifestFactory factory = new ManifestFactory( iLocSettings ); |
|
178 IThemeManifest manifest = factory.createManifest( iManifest ); |
|
179 |
|
180 // Install sub themes of a multi theme manifest, if any |
|
181 Enumeration manifests = manifest.getManifestFiles().elements(); |
|
182 if( manifests.hasMoreElements() ) |
|
183 { |
|
184 installMultiTheme( manifests ); |
|
185 } |
|
186 // Install a normal theme |
|
187 else |
|
188 { |
|
189 installTheme( manifest, iLocSettings ); |
|
190 } |
|
191 } |
|
192 } |
|
193 |
|
194 /* (non-Javadoc) |
|
195 * @see java.util.Observer#update(java.util.Observable, java.lang.Object) |
|
196 */ |
|
197 public void update( Observable aObservable, Object aEvent ) |
|
198 { |
|
199 // Language install event |
|
200 if( aObservable instanceof LanguageInstaller ) |
|
201 { |
|
202 // Notify that the parsing operation has completed and |
|
203 // the install of next language variant will start |
|
204 iLock.unLock(); |
|
205 |
|
206 LanguageInstallEvent event = ( LanguageInstallEvent )aEvent; |
|
207 ODTHeader header = event.getODTDocument().getODTHeader(); |
|
208 ProgressEvent pe = new ProgressEvent(); |
|
209 pe.setState( IInstallationListener.STATE_PARSED ); |
|
210 pe.setName( ( String )header.get( ODTHeader.ThemeShortName ) ); |
|
211 pe.setLanguage( ( |
|
212 ( Integer )header.get( ODTHeader.Language ) ).intValue() ); |
|
213 pe.setError( event.getErrorCode(), event.getReason() ); |
|
214 |
|
215 iListener.installationProgress( pe ); |
|
216 if( event.getErrorCode() == |
|
217 IParseOperationListener.OPERATION_SUCCESSFUL ) |
|
218 { |
|
219 InputStream in = null; |
|
220 try |
|
221 { |
|
222 // Store the ODT file |
|
223 ODTDocument document = event.getODTDocument(); |
|
224 in = new ODTInputStream( document ); |
|
225 |
|
226 // Source s = new DOMSource(document.getDOMDocument()); |
|
227 // |
|
228 // Result r = new StreamResult(new File("C://output.xml")); |
|
229 // |
|
230 // Transformer t = TransformerFactory.newInstance().newTransformer(); |
|
231 // |
|
232 // t.transform(s, r); |
|
233 |
|
234 iDefRep.storeODT( iDestinationDir, |
|
235 document.getODTHeader(), |
|
236 in, |
|
237 this ); |
|
238 } |
|
239 catch ( Exception e ) |
|
240 { |
|
241 pe.setError( IInstallationListener.ERROR, e.toString() ); |
|
242 iListener.installationCompleted( pe ); |
|
243 } |
|
244 finally |
|
245 { |
|
246 if( in != null ) |
|
247 { |
|
248 try |
|
249 { |
|
250 in.close(); |
|
251 } |
|
252 catch ( IOException e ) |
|
253 { |
|
254 // Ignore error |
|
255 } |
|
256 } |
|
257 } |
|
258 } |
|
259 else |
|
260 { |
|
261 pe.setError( event.getErrorCode(), event.getReason() ); |
|
262 iListener.installationCompleted( pe ); |
|
263 } |
|
264 } |
|
265 // File operation event |
|
266 else if( aObservable instanceof FileOperation ) |
|
267 { |
|
268 FileOperationEvent event = ( FileOperationEvent )aEvent; |
|
269 ProgressEvent pe = new ProgressEvent(); |
|
270 pe.setState( IInstallationListener.STATE_WRITED ); |
|
271 pe.setFileName( event.getFullDestPath() ); |
|
272 pe.setError( event.getErrorCode(), null ); |
|
273 |
|
274 if( event.getErrorCode() == FileOperationEvent.OPERATION_SUCCESSFUL ) |
|
275 { |
|
276 pe.setFileName( event.getFullDestPath() ); |
|
277 iListener.installationProgress( pe ); |
|
278 } |
|
279 else |
|
280 { |
|
281 pe.setError( event.getErrorCode(), null ); |
|
282 iListener.installationCompleted( pe ); |
|
283 } |
|
284 |
|
285 iList.removeInstall( event.getDestPath() ); |
|
286 if( !iList.installsExist() ) |
|
287 { |
|
288 pe.setError( event.getErrorCode(), null ); |
|
289 iListener.installationCompleted( pe ); |
|
290 } |
|
291 } |
|
292 } |
|
293 |
|
294 /* (non-Javadoc) |
|
295 * @see com.nokia.tools.themeinstaller.installationmanager.IInstallationListener#installationProgress(com.nokia.tools.themeinstaller.installationmanager.ProgressEvent) |
|
296 */ |
|
297 public void installationProgress( ProgressEvent aEvent ) |
|
298 { |
|
299 // Pass the event |
|
300 iListener.installationProgress( aEvent ); |
|
301 } |
|
302 |
|
303 /* (non-Javadoc) |
|
304 * @see com.nokia.tools.themeinstaller.installationmanager.IInstallationListener#installationCompleted(com.nokia.tools.themeinstaller.installationmanager.ProgressEvent) |
|
305 */ |
|
306 public void installationCompleted( ProgressEvent aEvent ) |
|
307 { |
|
308 // Pass the event and release the multi theme install lock |
|
309 iListener.installationCompleted( aEvent ); |
|
310 iMultiThemeLock.unLock(); |
|
311 } |
|
312 |
|
313 /** |
|
314 * Install a normal theme |
|
315 * @param aManifest Manifest file |
|
316 * @throws IOException if resource files can not be installed |
|
317 */ |
|
318 private void installTheme( IThemeManifest aManifest, File aLocSettings ) |
|
319 throws IOException |
|
320 { |
|
321 // Create unlocalized header for copying language independent resources |
|
322 ODTHeader unlocalizedHeader = |
|
323 LanguageInstaller.createHeader( aManifest, null ); |
|
324 Vector resources = aManifest.getResources(); |
|
325 Vector odtResources = |
|
326 iResourceInstaller.installResources( resources, unlocalizedHeader ); |
|
327 |
|
328 // Get all languages |
|
329 Enumeration languages = |
|
330 aManifest.getLanguages().elements(); |
|
331 |
|
332 // Install each language variant |
|
333 while( languages.hasMoreElements() ) |
|
334 { |
|
335 LanguageSpecificData language = |
|
336 ( LanguageSpecificData )languages.nextElement(); |
|
337 LanguageInstaller installer = new LanguageInstaller( |
|
338 this, aManifest, language, aLocSettings, iResourceInstaller ); |
|
339 |
|
340 // Add language id to the log |
|
341 iList.addInstall( language.getLanguageId() ); |
|
342 |
|
343 // Add language independent resources |
|
344 installer.addResources( odtResources ); |
|
345 |
|
346 try |
|
347 { |
|
348 // Start the installation process |
|
349 installer.install(); |
|
350 |
|
351 // Wait for the parsing process to complete |
|
352 iLock.lock(); |
|
353 } |
|
354 catch( Exception e ) |
|
355 { |
|
356 // In error cases, cancel the installation |
|
357 ProgressEvent pe = new ProgressEvent(); |
|
358 pe.setName( aManifest.getThemeShortName() ); |
|
359 pe.setLanguage( language.getLanguageId().intValue() ); |
|
360 pe.setError( IInstallationListener.ERROR, e.toString() ); |
|
361 iListener.installationCompleted( pe ); |
|
362 } |
|
363 } |
|
364 } |
|
365 |
|
366 /** |
|
367 * Install sub themes of a multi theme manifest. |
|
368 * @param aManifests List of manifests |
|
369 */ |
|
370 private void installMultiTheme( Enumeration aManifests ) |
|
371 { |
|
372 while( aManifests.hasMoreElements() ) |
|
373 { |
|
374 File f = ( File )aManifests.nextElement(); |
|
375 try |
|
376 { |
|
377 // Create installation parameters for the new |
|
378 // Installation Manager instance |
|
379 InstallationParameters params = new InstallationParameters( |
|
380 f, iDestinationDir ); |
|
381 params.setLocSettings( iLocSettings ); |
|
382 |
|
383 // Create a new installation manager |
|
384 InstallationManager i = new InstallationManager( params, this ); |
|
385 i.startInstallation(); |
|
386 |
|
387 // Install only a theme at a time |
|
388 iMultiThemeLock.lock(); |
|
389 } |
|
390 catch ( Exception e ) |
|
391 { |
|
392 // In error cases, cancel the installation |
|
393 ProgressEvent pe = new ProgressEvent(); |
|
394 pe.setFileName( f.getPath() ); |
|
395 pe.setError( IInstallationListener.ERROR, |
|
396 "Sub theme installation failed: " + e.toString() ); |
|
397 iListener.installationCompleted( pe ); |
|
398 } |
|
399 } |
|
400 |
|
401 } |
|
402 |
|
403 private Vector searchManifests( File aLocation ) |
|
404 { |
|
405 // Create a FilenameFilter class for searching manifest (.dat) files |
|
406 FilenameFilter filter = new FilenameFilter() |
|
407 { |
|
408 public boolean accept( File aDir, String aName ) |
|
409 { |
|
410 if( aName.endsWith( MANIFEST_SUFFIX ) ) |
|
411 { |
|
412 return true; |
|
413 } |
|
414 return false; |
|
415 } |
|
416 }; |
|
417 |
|
418 // List all manifest files in the directory and add them to |
|
419 // the result vector |
|
420 File[] files = aLocation.listFiles( filter ); |
|
421 Vector v = new Vector(); |
|
422 for( int i = 0; i < files.length; i++ ) |
|
423 { |
|
424 v.add( files[ i ] ); |
|
425 } |
|
426 |
|
427 return v; |
|
428 } |
|
429 |
|
430 } |