001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.editor.settings.storage;
043:
044: import java.beans.PropertyVetoException;
045: import java.io.File;
046: import java.io.FileOutputStream;
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.io.OutputStream;
050: import java.net.URL;
051: import java.util.ArrayList;
052: import java.util.MissingResourceException;
053: import java.util.ResourceBundle;
054: import junit.framework.Assert;
055: import org.openide.filesystems.AbstractFileSystem;
056: import org.openide.filesystems.DefaultAttributes;
057: import org.openide.filesystems.FileObject;
058: import org.openide.filesystems.FileSystem;
059: import org.openide.filesystems.JarFileSystem;
060: import org.openide.filesystems.LocalFileSystem;
061: import org.openide.filesystems.MultiFileSystem;
062: import org.openide.filesystems.Repository;
063: import org.openide.filesystems.XMLFileSystem;
064: import org.openide.loaders.DataFolder;
065: import org.openide.loaders.FolderLookup;
066: import org.openide.util.Lookup;
067: import org.openide.util.NbBundle;
068: import org.openide.util.lookup.Lookups;
069: import org.openide.util.lookup.ProxyLookup;
070:
071: /**
072: * Inspired by org.netbeans.api.project.TestUtil and FolderLookupTest
073: *
074: * @author Martin Roskanin
075: */
076: public class EditorTestLookup extends ProxyLookup {
077:
078: public static EditorTestLookup DEFAULT_LOOKUP = null;
079:
080: static {
081: EditorTestLookup.class.getClassLoader()
082: .setDefaultAssertionStatus(true);
083: System.setProperty("org.openide.util.Lookup",
084: EditorTestLookup.class.getName());
085: Assert.assertEquals(EditorTestLookup.class, Lookup.getDefault()
086: .getClass());
087: }
088:
089: public EditorTestLookup() {
090: Assert.assertNull(DEFAULT_LOOKUP);
091: DEFAULT_LOOKUP = this ;
092: }
093:
094: public static void setLookup(Object[] instances, ClassLoader cl,
095: FileObject servicesFolder, Class[] exclude) {
096: Lookup metaInfServices = Lookups.metaInfServices(cl);
097: if (exclude != null && exclude.length > 0) {
098: metaInfServices = Lookups.exclude(metaInfServices, exclude);
099: }
100:
101: DEFAULT_LOOKUP.setLookups(new Lookup[] {
102: Lookups.fixed(instances), metaInfServices,
103: Lookups.singleton(cl), });
104:
105: if (servicesFolder != null) {
106: // DataSystems need default repository, which is read from the default lookup.
107: // That's why the lookup is set first without the services lookup and then again
108: // here with the FolderLookup over the Services folder.
109: Lookup services = new FolderLookup(DataFolder
110: .findFolder(servicesFolder)).getLookup();
111: if (exclude != null && exclude.length > 0) {
112: services = Lookups.exclude(services, exclude);
113: }
114:
115: DEFAULT_LOOKUP.setLookups(new Lookup[] {
116: Lookups.fixed(instances), metaInfServices,
117: Lookups.singleton(cl), services });
118: }
119: }
120:
121: public static void setLookup(String[] files, File workDir,
122: Object[] instances, ClassLoader cl) throws IOException,
123: PropertyVetoException {
124: setLookup(files, workDir, instances, cl, null);
125: }
126:
127: public static void setLookup(String[] files, File workDir,
128: Object[] instances, ClassLoader cl, Class[] exclude)
129: throws IOException, PropertyVetoException {
130: FileSystem fs = createLocalFileSystem(workDir, files);
131: setLookup(new FileSystem[] { fs }, instances, cl, exclude);
132: }
133:
134: public static void setLookup(URL[] layers, File workDir,
135: Object[] instances, ClassLoader cl) throws IOException,
136: PropertyVetoException {
137: setLookup(layers, workDir, instances, cl, null);
138: }
139:
140: public static void setLookup(URL[] layers, File workDir,
141: Object[] instances, ClassLoader cl, Class[] exclude)
142: throws IOException, PropertyVetoException {
143: ArrayList<FileSystem> fs = new ArrayList<FileSystem>();
144: fs.add(createLocalFileSystem(workDir, new String[0]));
145:
146: ArrayList<URL> xmlLayers = new ArrayList<URL>();
147: for (URL layer : layers) {
148: if (layer.getPath().endsWith(".xml")) {
149: xmlLayers.add(layer);
150: } else if (layer.getPath().endsWith(".zip")) {
151: if (!xmlLayers.isEmpty()) {
152: XMLFileSystem layersFs = new XMLFileSystem();
153: layersFs.setXmlUrls(xmlLayers
154: .toArray(new URL[xmlLayers.size()]));
155: fs.add(layersFs);
156: xmlLayers.clear();
157: }
158:
159: fs.add(new ZipFileSystem(layer));
160: } else {
161: throw new IOException(
162: "Expecting .xml or .zip layers, but not '"
163: + layer.getPath() + "'");
164: }
165: }
166:
167: if (!xmlLayers.isEmpty()) {
168: XMLFileSystem layersFs = new XMLFileSystem();
169: layersFs.setXmlUrls(xmlLayers.toArray(new URL[xmlLayers
170: .size()]));
171: fs.add(layersFs);
172: }
173:
174: setLookup(fs.toArray(new FileSystem[fs.size()]), instances, cl,
175: exclude);
176: }
177:
178: private static void setLookup(FileSystem[] fs, Object[] instances,
179: ClassLoader cl, Class[] exclude) throws IOException,
180: PropertyVetoException {
181:
182: // Remember the tests run in the same VM and repository is singleton.
183: // Once it is created for the first time it will stick around forever.
184: Repository repository = (Repository) Lookup.getDefault()
185: .lookup(Repository.class);
186: if (repository == null) {
187: repository = new Repository(new SystemFileSystem(fs));
188: } else {
189: ((SystemFileSystem) repository.getDefaultFileSystem())
190: .setOrig(fs);
191: }
192:
193: Object[] lookupContent = new Object[instances.length + 1];
194: lookupContent[0] = repository;
195: System.arraycopy(instances, 0, lookupContent, 1,
196: instances.length);
197:
198: // Create the Services folder (if needed}
199: FileObject services = repository.getDefaultFileSystem()
200: .findResource("Services");
201: if (services == null) {
202: services = repository.getDefaultFileSystem().getRoot()
203: .createFolder("Services");
204: }
205:
206: DEFAULT_LOOKUP.setLookup(lookupContent, cl, services, exclude);
207: }
208:
209: private static FileSystem createLocalFileSystem(File mountPoint,
210: String[] resources) throws IOException {
211: mountPoint.mkdir();
212:
213: for (int i = 0; i < resources.length; i++) {
214: createFileOnPath(mountPoint, resources[i]);
215: }
216:
217: LocalFileSystem lfs = new LocalFileSystem();
218: try {
219: lfs.setRootDirectory(mountPoint);
220: } catch (Exception ex) {
221: }
222:
223: return lfs;
224: }
225:
226: private static void createFileOnPath(File mountPoint, String path)
227: throws IOException {
228: mountPoint.mkdir();
229:
230: File f = new File(mountPoint, path);
231: if (f.isDirectory() || path.endsWith("/")) {
232: f.mkdirs();
233: } else {
234: f.getParentFile().mkdirs();
235: try {
236: f.createNewFile();
237: } catch (IOException iex) {
238: throw new IOException("While creating " + path + " in "
239: + mountPoint.getAbsolutePath() + ": "
240: + iex.toString() + ": " + f.getAbsolutePath());
241: }
242: }
243: }
244:
245: private static class SystemFileSystem extends MultiFileSystem
246: implements FileSystem.Status {
247: public SystemFileSystem(FileSystem[] orig) {
248: super (orig);
249: }
250:
251: public void setOrig(FileSystem[] orig) {
252: setDelegates(orig);
253: }
254:
255: public FileSystem.Status getStatus() {
256: return this ;
257: }
258:
259: public String annotateName(String name, java.util.Set files) {
260: for (Object o : files) {
261: FileObject fo = (FileObject) o;
262: String bundleName = (String) fo
263: .getAttribute("SystemFileSystem.localizingBundle"); // NOI18N
264: if (bundleName != null) {
265: bundleName = org.openide.util.Utilities
266: .translate(bundleName);
267: ResourceBundle b = NbBundle.getBundle(bundleName);
268: try {
269: return b.getString(fo.getPath());
270: } catch (MissingResourceException ex) {
271: // ignore--normal
272: ex.printStackTrace();
273: }
274: }
275: }
276:
277: return name;
278: }
279:
280: public java.awt.Image annotateIcon(java.awt.Image icon,
281: int iconType, java.util.Set files) {
282: return icon;
283: }
284: } // End of SystemFileSystem class
285:
286: private static final class ZipFileSystem extends AbstractFileSystem {
287:
288: private final String zipPath;
289:
290: public ZipFileSystem(URL zipURL) throws IOException {
291: this .zipPath = zipURL.toString();
292:
293: File zipFile = File.createTempFile("ZipFileSystem", ".zip");
294: zipFile.deleteOnExit();
295:
296: OutputStream os = new FileOutputStream(zipFile);
297: try {
298: InputStream is = zipURL.openStream();
299: try {
300: byte[] buffer = new byte[1024];
301: int size;
302: while (0 < (size = is
303: .read(buffer, 0, buffer.length))) {
304: os.write(buffer, 0, size);
305: }
306: } finally {
307: is.close();
308: }
309: } finally {
310: os.close();
311: }
312:
313: JarFileSystem jfs = new JarFileSystem();
314: try {
315: jfs.setJarFile(zipFile);
316: } catch (PropertyVetoException pve) {
317: IOException ioe = new IOException();
318: ioe.initCause(pve);
319: throw ioe;
320: }
321:
322: JarFileSystem.Impl jfsImpl = new JarFileSystem.Impl(jfs);
323: DefaultAttributes attribs = new DefaultAttributes(jfsImpl,
324: jfsImpl, jfsImpl);
325:
326: this .info = jfsImpl;
327: this .change = jfsImpl;
328: this .list = attribs;
329: this .attr = attribs;
330: }
331:
332: public String getDisplayName() {
333: return "ZipFileSystem[" + zipPath;
334: }
335:
336: public boolean isReadOnly() {
337: return true;
338: }
339: } // End of ZipFileSystem class
340: }
|