PageRenderTime 83ms CodeModel.GetById 50ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/net/sourceforge/jarbundler/PropertyListWriter.java

#
Java | 442 lines | 241 code | 130 blank | 71 comment | 53 complexity | 068d85a91bc468112f9aed2f5ce8b73d MD5 | raw file
  1/*
  2 * Write the application bundle file: Info.plist
  3 *
  4 * Copyright (c) 2006, William A. Gilbert <gilbert@informagen.com> All rights reserved.
  5 *
  6 * This program is free software; you can redistribute it and/or modify it
  7 * under the terms of the GNU General Public License as published by the Free
  8 * Software Foundation; either version 2 of the License, or (at your option)
  9 * any later version.
 10 *
 11 * This program is distributed in the hope that it will be useful, but WITHOUT
 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13 * FITNESS FOR A PARTICULAR PURPOSE.  See  the GNU General Public License for
 14 * more details.
 15 *
 16 * You should have received a copy of the GNU General Public License along with
 17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 18 * Place - Suite 330, Boston, MA  02111-1307, USA.
 19 */
 20
 21package net.sourceforge.jarbundler;
 22
 23// This package's imports
 24import net.sourceforge.jarbundler.AppBundleProperties;
 25
 26// Java I/O
 27import java.io.BufferedWriter;
 28import java.io.File;
 29import java.io.FileOutputStream;
 30import java.io.IOException;
 31import java.io.OutputStreamWriter;
 32import java.io.Writer;
 33
 34// Java Utility
 35import java.util.Hashtable;
 36import java.util.Iterator;
 37import java.util.List;
 38
 39// Java language imports
 40import java.lang.Boolean;
 41import java.lang.ClassCastException;
 42import java.lang.Double;
 43import java.lang.String;
 44import java.lang.System;
 45
 46// Apache Ant
 47import org.apache.tools.ant.BuildException;
 48import org.apache.tools.ant.util.FileUtils;
 49
 50// Java XML DOM creation
 51import javax.xml.parsers.DocumentBuilderFactory;
 52import javax.xml.parsers.DocumentBuilder;
 53import javax.xml.parsers.ParserConfigurationException;
 54
 55// W3C DOM
 56import org.w3c.dom.Document;
 57import org.w3c.dom.DOMImplementation;
 58import org.w3c.dom.Node;
 59import org.w3c.dom.Element;
 60import org.w3c.dom.Attr;
 61
 62
 63// Xerces serializer
 64import org.apache.xml.serialize.OutputFormat;
 65import org.apache.xml.serialize.XMLSerializer;
 66import org.apache.xml.serialize.LineSeparator;
 67
 68
 69
 70/**
 71 * Write out a Java application bundle property list file. For descriptions of
 72 * the property list keys, see <a
 73 * href="http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/PListKeys.html"
 74 * >Apple docs</a>.
 75 */
 76
 77
 78public class PropertyListWriter {
 79
 80
 81	// Our application bundle properties
 82	private AppBundleProperties bundleProperties;
 83
 84	private double version = 1.3;
 85
 86	// DOM version of Info.plist file
 87	private Document document = null;
 88
 89
 90	private FileUtils fileUtils = FileUtils.getFileUtils();
 91	
 92	/**
 93	 * Create a new Property List writer.
 94	 */
 95	public PropertyListWriter(AppBundleProperties bundleProperties) {
 96		this.bundleProperties = bundleProperties;
 97		setJavaVersion(bundleProperties.getJVMVersion());
 98	}
 99
100	private void setJavaVersion(String version) {
101
102		if (version == null)
103			return;
104
105		this.version = Double.valueOf(version.substring(0, 3)).doubleValue();
106	}
107
108
109	public void writeFile(File fileName) throws BuildException {
110
111		Writer writer = null;
112
113		try {
114
115			this.document = createDOM();
116			buildDOM();
117
118			// Serialize the DOM into the writer
119			writer = new BufferedWriter(new OutputStreamWriter(
120			                            new FileOutputStream(fileName), "UTF-8"));
121			// Prettify the XML Two space indenting, no line wrapping
122			OutputFormat outputFormat = new OutputFormat();
123			outputFormat.setMethod("xml");
124			outputFormat.setIndenting(true);
125			outputFormat.setIndent(2);
126			outputFormat.setLineWidth(0);             
127			
128			// Create a DOM serlializer and write the XML
129			XMLSerializer serializer = new XMLSerializer(writer, outputFormat);
130			serializer.asDOMSerializer();
131			serializer.serialize(this.document);
132
133		} catch (ParserConfigurationException pce) {
134			throw new BuildException(pce);
135		} catch (IOException ex) {
136			throw new BuildException("Unable to write  \"" + fileName + "\"");
137		} finally {
138			fileUtils.close(writer);
139		}
140
141
142	}
143
144	private Document createDOM() throws ParserConfigurationException {
145	
146		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
147		DocumentBuilder documentBuilder = factory.newDocumentBuilder();
148		DOMImplementation domImpl = documentBuilder.getDOMImplementation();
149
150		// We needed to reference using the full class name here because we already have 
151		//  a class named "DocumentType"
152		
153		org.w3c.dom.DocumentType doctype = domImpl.createDocumentType(
154		       "plist",
155		       "-//Apple Computer//DTD PLIST 1.0//EN",
156		       "http://www.apple.com/DTDs/PropertyList-1.0.dtd");
157
158		return domImpl.createDocument(null, "plist", doctype);
159	}
160
161
162	private void buildDOM()  {
163
164		Element plist = this.document.getDocumentElement();
165		plist.setAttribute("version","1.0");		
166
167		// Open the top level dictionary, <dict>
168		
169		Node dict = createNode("dict", plist);
170
171		// Application short name i.e. About menu name
172		writeKeyStringPair("CFBundleName", bundleProperties.getCFBundleName(), dict);
173
174		// Finder 'Version' label, defaults to "1.0"
175		writeKeyStringPair("CFBundleShortVersionString", bundleProperties.getCFBundleShortVersionString(), dict);
176		
177		// Finder 'Get Info'
178		writeKeyStringPair("CFBundleGetInfoString", bundleProperties.getCFBundleGetInfoString(), dict);
179		
180		// Mac OS X required key, defaults to "false"
181		writeKeyStringPair("CFBundleAllowMixedLocalizations", 
182		     (bundleProperties.getCFBundleAllowMixedLocalizations() ? "true" : "false"),  
183		     dict);
184
185		// Mac OS X required, defaults to "6.0"
186		writeKeyStringPair("CFBundleInfoDictionaryVersion", 
187		     bundleProperties.getCFBundleInfoDictionaryVersion(), dict);
188
189		// Bundle Executable name, required, defaults to "JavaApplicationStub"
190		writeKeyStringPair("CFBundleExecutable", bundleProperties.getCFBundleExecutable(), dict);
191
192		// Bundle Development Region, required, defaults to "English"
193		writeKeyStringPair("CFBundleDevelopmentRegion", bundleProperties.getCFBundleDevelopmentRegion(), dict);
194
195		// Bundle Package Type, required, defaults tp "APPL"
196		writeKeyStringPair("CFBundlePackageType", bundleProperties.getCFBundlePackageType(), dict);
197
198		// Bundle Signature, required, defaults tp "????"
199		writeKeyStringPair("CFBundleSignature", bundleProperties.getCFBundleSignature(), dict);
200
201		// Application build number, optional
202		if (bundleProperties.getCFBundleVersion() != null) 
203			writeKeyStringPair("CFBundleVersion", bundleProperties.getCFBundleVersion(), dict);
204		
205		// Application Icon file, optional
206		if (bundleProperties.getCFBundleIconFile() != null) 
207			writeKeyStringPair("CFBundleIconFile", bundleProperties.getCFBundleIconFile(), dict);
208
209		// Bundle Identifier, optional
210		if (bundleProperties.getCFBundleIdentifier() != null) 
211			writeKeyStringPair("CFBundleIdentifier", bundleProperties.getCFBundleIdentifier(), dict);
212
213		// Help Book Folder, optional
214		if (bundleProperties.getCFBundleHelpBookFolder() != null) 
215			writeKeyStringPair("CFBundleHelpBookFolder", bundleProperties.getCFBundleHelpBookFolder(), dict);
216
217		// Help Book Name, optional
218		if (bundleProperties.getCFBundleHelpBookName() != null) 
219			writeKeyStringPair("CFBundleHelpBookName", bundleProperties.getCFBundleHelpBookName(), dict);
220
221		// Document Types, optional
222		List documentTypes = bundleProperties.getDocumentTypes();
223
224		if (documentTypes.size() > 0) 
225 			writeDocumentTypes(documentTypes, dict);
226
227		// Java entry in the plist dictionary
228		writeKey("Java", dict);
229		Node javaDict = createNode("dict", dict);
230
231		// Main class, required
232		writeKeyStringPair("MainClass", bundleProperties.getMainClass(), javaDict);
233
234		// Target JVM version, optional but recommended
235		if (bundleProperties.getJVMVersion() != null) 
236			writeKeyStringPair("JVMVersion", bundleProperties.getJVMVersion(), javaDict);
237
238
239		// Classpath is composed of two types, required
240		// 1: Jars bundled into the JAVA_ROOT of the application
241		// 2: External directories or files with an absolute path
242
243		List classPath = bundleProperties.getClassPath();
244		List extraClassPath = bundleProperties.getExtraClassPath();
245
246		if ((classPath.size() > 0) || (extraClassPath.size() > 0)) 
247			writeClasspath(classPath, extraClassPath, javaDict);
248		
249
250		// JVM options, optional
251		if (bundleProperties.getVMOptions() != null) 
252			writeKeyStringPair("VMOptions", bundleProperties.getVMOptions(), javaDict);
253
254		// Working directory, optional
255		if (bundleProperties.getWorkingDirectory() != null) 
256			writeKeyStringPair("WorkingDirectory", bundleProperties.getWorkingDirectory(), javaDict);
257
258		// Main class arguments, optional
259		if (bundleProperties.getArguments() != null) 
260			writeKeyStringPair("Arguments", bundleProperties.getArguments(), javaDict);
261
262		// Java properties, optional
263		Hashtable javaProperties = bundleProperties.getJavaProperties();
264
265		if (javaProperties.isEmpty() == false) 
266 			writeJavaProperties(javaProperties, javaDict);
267
268
269		// Services, optional
270		List services = bundleProperties.getServices();
271		if (services.size() > 0) 
272 			writeServices(services,dict);
273		
274	}
275
276
277	private void writeDocumentTypes(List documentTypes, Node appendTo) {
278
279		writeKey("CFBundleDocumentTypes", appendTo);
280		
281		Node array = createNode("array", appendTo);
282
283		Iterator itor = documentTypes.iterator();
284
285		while (itor.hasNext()) {
286
287			DocumentType documentType = (DocumentType) itor.next();
288
289			Node documentDict = createNode("dict", array);
290
291			writeKeyStringPair("CFBundleTypeName", documentType.getName(), documentDict);
292			writeKeyStringPair("CFBundleTypeRole", documentType.getRole(), documentDict);
293
294			File iconFile = documentType.getIconFile();
295
296			if (iconFile != null)
297				writeKeyStringPair("CFBundleTypeIconFile", iconFile.getName(), documentDict);
298
299
300			List extensions = documentType.getExtensions();
301
302			if (extensions.isEmpty() == false) {
303				writeKey("CFBundleTypeExtensions", documentDict);
304				writeArray(extensions, documentDict);
305			}
306
307			List osTypes = documentType.getOSTypes();
308
309			if (osTypes.isEmpty() == false) {
310				writeKey("CFBundleTypeOSTypes", documentDict);
311				writeArray(osTypes, documentDict);
312			}
313
314			
315			List mimeTypes = documentType.getMimeTypes();
316
317			if (mimeTypes.isEmpty() == false) {
318				writeKey("CFBundleTypeMIMETypes", documentDict);
319				writeArray(mimeTypes, documentDict);
320			}
321
322			// Only write this key if true
323			if (documentType.isBundle()) 
324				writeKeyStringPair("LSTypeIsPackage", "true", documentDict);
325		}
326	}
327	
328	private void writeServices(List services, Node appendTo) {
329	
330		writeKey("NSServices",appendTo);
331		Node array = createNode("array",appendTo);
332		Iterator itor = services.iterator();
333		
334		while (itor.hasNext()) {
335			Service service = (Service)itor.next();
336			Node serviceDict = createNode("dict",array);
337
338			String portName = service.getPortName();
339            if (portName == null)
340            	portName = bundleProperties.getCFBundleName();
341			
342			writeKeyStringPair("NSPortName", portName, serviceDict);
343			writeKeyStringPair("NSMessage",service.getMessage(),serviceDict);
344			
345			List sendTypes = service.getSendTypes();
346			if (!sendTypes.isEmpty()) {
347				writeKey("NSSendTypes",serviceDict);
348				writeArray(sendTypes,serviceDict);
349			}
350			
351			List returnTypes = service.getReturnTypes();
352			if (!returnTypes.isEmpty()) {
353				writeKey("NSReturnTypes",serviceDict);
354				writeArray(returnTypes,serviceDict);
355			}
356			
357			writeKey("NSMenuItem",serviceDict);
358			Node menuItemDict = createNode("dict",serviceDict);
359			writeKeyStringPair("default",service.getMenuItem(),menuItemDict);
360			
361			String keyEquivalent = service.getKeyEquivalent();
362			if (null != keyEquivalent) {
363				writeKey("NSKeyEquivalent",serviceDict);
364				Node keyEquivalentDict = createNode("dict",serviceDict);
365				writeKeyStringPair("default",keyEquivalent,keyEquivalentDict);
366			}
367			
368			String userData = service.getUserData();
369			if (null != userData)
370				writeKeyStringPair("NSUserData", userData, serviceDict);
371			
372			String timeout = service.getTimeout();
373			if (null != timeout)
374				writeKeyStringPair("NSTimeout",timeout,serviceDict);
375 		}
376	}
377
378	private void writeClasspath(List classpath, List extraClasspath, Node appendTo) {
379		writeKey("ClassPath", appendTo);
380		classpath.addAll(extraClasspath);
381		writeArray(classpath, appendTo);
382	}
383
384
385	private void writeJavaProperties(Hashtable javaProperties, Node appendTo) {
386	
387		writeKey("Properties", appendTo);
388		
389		Node propertiesDict = createNode("dict", appendTo);
390
391		for (Iterator i = javaProperties.keySet().iterator(); i.hasNext();) {
392			String key = (String) i.next();
393
394			if (key.startsWith("com.apple.") && (version >= 1.4)) {
395				System.out.println("Deprecated as of 1.4: " + key);
396				continue;
397			}
398
399			writeKeyStringPair(key, (String)javaProperties.get(key), propertiesDict);
400		}
401	}
402
403	private Node createNode(String tag, Node appendTo) {
404		Node node = this.document.createElement(tag);
405		appendTo.appendChild(node);
406		return node;
407	}
408
409
410	private void writeKeyStringPair(String key, String string, Node appendTo) {
411	
412		if (string == null)
413			return;
414	
415		writeKey(key, appendTo);
416		writeString(string, appendTo);
417	}
418
419
420	private void writeKey(String key, Node appendTo) {
421		Element keyNode = this.document.createElement("key");
422		appendTo.appendChild(keyNode);
423		keyNode.appendChild(this.document.createTextNode(key));
424	}
425
426
427	private void writeString(String string, Node appendTo) {
428		Element stringNode = this.document.createElement("string");
429		stringNode.appendChild(this.document.createTextNode(string));
430		appendTo.appendChild(stringNode);
431	}
432
433	private void writeArray(List stringList, Node appendTo) {
434	
435		Node arrayNode = createNode("array", appendTo);	
436
437		for (Iterator it = stringList.iterator(); it.hasNext();) 
438			writeString((String)it.next(), arrayNode);
439		
440	}
441
442}