001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.shell.moz;
017:
018: import com.google.gwt.util.tools.Utility;
019:
020: import java.io.BufferedReader;
021: import java.io.File;
022: import java.io.FileNotFoundException;
023: import java.io.FileReader;
024: import java.io.IOException;
025:
026: /**
027: * Utility class to represent a Mozilla installation, including its installation
028: * directory and a load order file. Instances are immutable, and static helper
029: * functions are provided to create instances.
030: */
031: public class MozillaInstall {
032:
033: // Default hosted browser config file.
034: private static final String CONFIG_FILENAME = "mozilla-hosted-browser.conf";
035:
036: // Default load order file (optional).
037: private static final String LOAD_ORDER_CONFIG_FILE = "gwt-dl-loadorder.conf";
038:
039: // Mozilla installation which was actually loaded.
040: private static MozillaInstall loadedInstallation = null;
041:
042: /**
043: * Find a suitable mozilla install for GWT hosted mode.
044: *
045: * This is done by reading the mozilla-hosted-browser.conf in the install
046: * directory, which contains one or more entries, each describing a Mozilla
047: * install to try and load. The first suitable (present and compiled against
048: * GTK2 instead of GTK1) one found is used.
049: *
050: * Blank lines and lines beginning with # are ignored. The install directory
051: * is prepended to non-absolute paths.
052: *
053: * @return a MozillaInstall instance or <code>null</code> if none could be
054: * found
055: */
056: public static MozillaInstall find() {
057: String installPath = Utility.getInstallPath();
058: try {
059: // try to make absolute
060: installPath = new File(installPath).getCanonicalPath();
061: } catch (IOException e) {
062: /*
063: * We might have an exception here if a parent directory is not readable,
064: * so leave it non-absolute and hope the relative path works. If this
065: * fails, the libraries will fail to load when SWT initializes.
066: */
067: }
068:
069: /*
070: * Read from the mozilla-hosted-browser.conf file and try to find a suitable
071: * mozilla installation. Return immediately if a suitable one is found.
072: */
073: try {
074: BufferedReader reader = new BufferedReader(new FileReader(
075: installPath + "/" + CONFIG_FILENAME));
076: try { // make sure we close the reader
077: String mozillaDir;
078: while ((mozillaDir = reader.readLine()) != null) {
079: if (mozillaDir.startsWith("#")
080: || mozillaDir.matches("^\\s*$")) {
081: // lines beginning with # are comments, ignore blank lines
082: continue;
083: }
084: if (!mozillaDir.startsWith("/")) {
085: mozillaDir = installPath + "/" + mozillaDir;
086: }
087: MozillaInstall mozInstall = new MozillaInstall(
088: mozillaDir);
089: if (mozInstall.isAcceptable()) {
090: return mozInstall;
091: }
092: }
093: } finally {
094: reader.close();
095: }
096: } catch (FileNotFoundException e) {
097: // fall through to common error-path code
098: } catch (IOException e) {
099: // fall through to common error-path code
100: }
101:
102: // if we get here, nothing worked. Return failure.
103: return null;
104: }
105:
106: /**
107: * @return the installation which was loaded, or null if none
108: */
109: public static MozillaInstall getLoaded() {
110: return loadedInstallation;
111: }
112:
113: /**
114: * The absolute path to a directory containing a Mozilla install.
115: */
116: private String path;
117:
118: /**
119: * Create a new instance. Private since this should only be created via the
120: * find factory method.
121: *
122: * @param path absolute path to the directory containing the Mozilla install
123: */
124: private MozillaInstall(String path) {
125: this .path = path;
126: }
127:
128: /**
129: * @return the path of this Mozilla install
130: */
131: public String getPath() {
132: return path;
133: }
134:
135: /**
136: * Load any libraries required for this Mozilla install, reading from the
137: * loadOrderFile.
138: *
139: * The format of the load order configuration file is simply one library path
140: * per line (if non-absolute, the install directory is prepended) to be
141: * loaded. This is necessary because we have to forcibly load some libraries
142: * to make sure they are used instead of system-supplied libraries.
143: *
144: * Blank lines and lines beginning with # are ignored.
145: *
146: * @throws UnsatisfiedLinkError if libxpcom.so failed to load
147: */
148: public void load() {
149: try {
150: /*
151: * Read the library load order configuration file to get the list of
152: * libraries which must be preloaded. This is required because Eclipse
153: * seems to always add the system mozilla directory to the
154: * java.library.path, which results in loading the system-supplied
155: * libraries to fulfill dependencies rather than the ones we supply. So,
156: * to get around this we preload individual libraries in a particular
157: * order to make sure they get pulled in properly.
158: *
159: * The file has one line per library, each giving either an absolute path
160: * or a path relative to the browser directory, in the order the libraries
161: * should be loaded.
162: */
163: String loadOrderFile = path + "/" + LOAD_ORDER_CONFIG_FILE;
164: BufferedReader reader = new BufferedReader(new FileReader(
165: loadOrderFile));
166: try {
167: // read each line and load the library specified
168: String library;
169: while ((library = reader.readLine()) != null) {
170: if (library.startsWith("#")
171: || library.matches("^\\s*$")) {
172: // lines beginning with # are comments, ignore blank lines
173: continue;
174: }
175: if (!library.startsWith("/")) {
176: library = path + "/" + library;
177: }
178: System.load(library);
179: }
180: } finally {
181: reader.close();
182: }
183: } catch (FileNotFoundException e) {
184: // ignore error, assume system will load libraries properly
185: } catch (IOException e) {
186: // ignore error, assume system will load libraries properly
187: }
188: /*
189: * Forcibly load libxpcom.so. Since it has to be loaded before SWT loads its
190: * swt-mozilla library, load it here. This will also cause a failure early
191: * in the process if we have a problem rather than waiting until SWT starts
192: * up.
193: */
194: System.load(path + "/libxpcom.so");
195: loadedInstallation = this ;
196: }
197:
198: /**
199: * Checks to see if the specified path refers to an acceptable Mozilla
200: * install.
201: *
202: * In this case, acceptable means it is present and was not compiled against
203: * GTK1.
204: *
205: * Note: Embedding a Mozilla GTK1.2 causes a crash. The workaround is to check
206: * the version of GTK used by Mozilla by looking for the libwidget_gtk.so
207: * library used by Mozilla GTK1.2. Mozilla GTK2 uses the libwidget_gtk2.so
208: * library.
209: *
210: * @return <code>true</code> if this Mozilla installation is acceptable for
211: * use with GWT
212: */
213: private boolean isAcceptable() {
214: // make sure the main library exists
215: if (!new File(path, "libxpcom.so").exists()) {
216: return false;
217: }
218: // check to see if it was built against GTK1 instead of GTK2
219: if (new File(path, "components/libwidget_gtk.so").exists()) {
220: return false;
221: }
222: return true;
223: }
224: }
|