2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.editor.mimelookup.impl;
44
import java.beans.PropertyChangeEvent;
45
import java.beans.PropertyChangeListener;
46
import java.io.IOException;
47
import java.lang.ref.Reference;
48
import java.lang.ref.WeakReference;
49
import java.lang.reflect.Method;
50
import java.util.ArrayList;
51
import java.util.List;
52
import java.util.logging.Level;
53
import java.util.logging.Logger;
54
import org.openide.cookies.InstanceCookie;
55
import org.openide.filesystems.FileObject;
56
import org.openide.loaders.DataObject;
57
import org.openide.loaders.DataObjectNotFoundException;
58
import org.openide.loaders.InstanceDataObject;
59
import org.openide.util.Exceptions;
60
import org.openide.util.lookup.AbstractLookup;
61
import org.openide.util.lookup.InstanceContent;
67
public final class FolderPathLookup extends AbstractLookup {
69
private static final Logger LOG = Logger.getLogger(FolderPathLookup.class.getName());
71
private InstanceContent content;
73
private CompoundFolderChildren children;
74
private PCL listener = new PCL();
76
// private final InstanceConvertor CONVERTOR = new InstanceConvertor();
78
/** Creates a new instance of InstanceProviderLookup */
79
public FolderPathLookup(String [] paths) {
80
this(paths, new InstanceContent());
83
private FolderPathLookup(String [] paths, InstanceContent content) {
86
this.content = content;
88
this.children = new CompoundFolderChildren(paths, false);
89
this.children.addPropertyChangeListener(listener);
94
private void rebuild() {
95
List<ICItem> instanceFiles = new ArrayList<ICItem>();
97
for (FileObject file : children.getChildren()) {
98
if (!file.isValid()) {
99
// Can happen after modules are disabled. Ignore it.
104
DataObject d = DataObject.find(file);
105
InstanceCookie instanceCookie = d.getCookie(InstanceCookie.class);
106
if (instanceCookie != null) {
107
instanceFiles.add(new ICItem(d, instanceCookie));
109
} catch (Exception e) {
110
LOG.log(Level.WARNING, "Can't create DataObject", e); //NOI18N
114
// System.out.println("Setting instanceFiles for FolderPathLookup@" + System.identityHashCode(this) + " {");
115
// for (Iterator i = instanceFiles.iterator(); i.hasNext(); ) {
116
// String filePath = (String) i.next();
117
// System.out.println(" '" + filePath);
119
// System.out.println("} End of Setting instanceFiles for FolderPathLookup@" + System.identityHashCode(this) + " -----------------------------");
121
content.setPairs(instanceFiles);
124
private class PCL implements PropertyChangeListener {
125
public void propertyChange(PropertyChangeEvent evt) {
128
} // End of PCL class
131
// XXX: this is basically a copy of FolderLookup.ICItem, see #104705
133
/** Item that delegates to <code>InstanceCookie</code>. Item which
134
* the internal lookup data structure is made from. */
135
private static final class ICItem extends AbstractLookup.Pair {
136
static final long serialVersionUID = 10L;
138
static final ThreadLocal<ICItem> DANGEROUS = new ThreadLocal<ICItem> ();
140
/** error manager for ICItem */
141
private static final Logger ERR = Logger.getLogger(ICItem.class.getName());
143
/** when deserialized only primary file is stored */
144
private FileObject fo;
146
private transient InstanceCookie ic;
147
/** source data object */
148
private transient DataObject dataObject;
149
/** reference to created object */
150
private transient Reference<Object> ref;
152
/** Constructs new item. */
153
public ICItem (DataObject obj, InstanceCookie ic) {
155
this.dataObject = obj;
156
this.fo = obj.getPrimaryFile();
158
if (ERR.isLoggable(Level.FINE)) ERR.fine("New ICItem: " + obj); // NOI18N
161
/** Initializes the item
163
public void init () {
164
if (ic != null) return;
166
ICItem prev = DANGEROUS.get ();
168
DANGEROUS.set (this);
169
if (dataObject == null) {
171
dataObject = DataObject.find(fo);
172
} catch (DataObjectNotFoundException donfe) {
173
ic = new BrokenInstance("No DataObject for " + fo.getPath(), donfe); // NOI18N
178
ic = dataObject.getCookie (InstanceCookie.class);
180
ic = new BrokenInstance("No cookie for " + fo.getPath(), null); // NOI18N
183
DANGEROUS.set (prev);
188
* Fake instance cookie.
189
* Used in case a file had an instance in a previous session but now does not
190
* (or the data object could not even be created correctly).
192
private static final class BrokenInstance implements InstanceCookie.Of {
193
private final String message;
194
private final Exception ex;
195
public BrokenInstance(String message, Exception ex) {
196
this.message = message;
199
public String instanceName() {
200
return "java.lang.Object"; // NOI18N
202
private ClassNotFoundException die() {
204
return new ClassNotFoundException(message, ex);
206
return new ClassNotFoundException(message);
209
public Class instanceClass() throws IOException, ClassNotFoundException {
212
public Object instanceCreate() throws IOException, ClassNotFoundException {
215
public boolean instanceOf(Class type) {
221
/** The class of the result item.
222
* @return the class of the item
224
protected boolean instanceOf (Class clazz) {
227
if (ERR.isLoggable(Level.FINE)) ERR.fine("instanceOf: " + clazz.getName() + " obj: " + dataObject); // NOI18N
229
if (ic instanceof InstanceCookie.Of) {
230
// special handling for special cookies
231
InstanceCookie.Of of = (InstanceCookie.Of)ic;
232
boolean res = of.instanceOf (clazz);
233
if (ERR.isLoggable(Level.FINE)) ERR.fine(" of: " + res); // NOI18N
237
// handling of normal instance cookies
239
@SuppressWarnings("unchecked")
240
boolean res = clazz.isAssignableFrom (ic.instanceClass ());
241
if (ERR.isLoggable(Level.FINE)) ERR.fine(" plain: " + res); // NOI18N
243
} catch (ClassNotFoundException ex) {
245
} catch (IOException ex) {
251
/** The class of the result item.
252
* @return the instance of the object or null if it cannot be created
254
public Object getInstance() {
258
Object obj = ic.instanceCreate();
259
if (ERR.isLoggable(Level.FINE)) ERR.fine(" getInstance: " + obj + " for " + this.dataObject); // NOI18N
260
ref = new WeakReference<Object> (obj);
262
} catch (ClassNotFoundException ex) {
264
} catch (IOException ex) {
270
/** Hash code is the <code>InstanceCookie</code>'s code. */
271
public @Override int hashCode () {
274
return System.identityHashCode (ic);
277
/** Two items are equal if they point to the same cookie. */
278
public @Override boolean equals (Object obj) {
279
if (obj instanceof ICItem) {
280
ICItem i = (ICItem)obj;
288
/** An identity of the item.
289
* @return string representing the item, that can be used for
290
* persistance purposes to locate the same item next time */
291
public String getId() {
294
if (dataObject == null) {
296
return "<broken: " + fo.getPath() + ">"; // NOI18N
299
return dataObject.getName();
302
/** Display name is extracted from name of the objects node. */
303
public String getDisplayName () {
306
if (dataObject == null) {
308
return "<broken: " + fo.getPath() + ">"; // NOI18N
311
return dataObject.getNodeDelegate ().getDisplayName ();
314
/** Method that can test whether an instance of a class has been created
317
* @param obj the instance
318
* @return if the item has already create an instance and it is the same
321
protected boolean creatorOf(Object obj) {
323
if (w != null && w.get () == obj) {
326
if (this.dataObject instanceof InstanceDataObject) {
328
Method m = InstanceDataObject.class.getDeclaredMethod("creatorOf", Object.class); //NOI18N
329
return (Boolean) m.invoke(this.dataObject, obj);
330
} catch (Exception e) {
337
/** The class of this item.
338
* @return the correct class
340
public Class getType() {
344
return ic.instanceClass ();
345
} catch (IOException ex) {
346
// ok, no class available
347
} catch (ClassNotFoundException ex) {
348
// ok, no class available
353
private static void exception(Exception e, FileObject fo) {
354
Exceptions.attachMessage(e, "Bad file: " + fo); // NOI18N
355
LOG.log(Level.WARNING, null, e);
357
} // End of ICItem class.
359
// private static final class InstanceConvertor implements InstanceContent.Convertor<String,Object> {
360
// private Map<String,Reference<Class<?>>> types = new HashMap<String,Reference<Class<?>>>();
362
// public Class<?> type(String filePath) {
363
// synchronized (types) {
364
// Reference<Class<?>> ref = types.get(filePath);
365
// Class<?> type = ref == null ? null : (Class) ref.get();
366
// if (type == null) {
368
// type = getInstanceCookie(filePath).instanceClass();
369
// types.put(filePath, new WeakReference<Class<?>>(type));
370
// } catch (Exception e) {
371
// LOG.log(Level.WARNING, "Can't determine instance class from '" + filePath + "'", e); //NOI18N
372
// return DeadMarker.class; // Something nobody will ever find
380
// public String id(String filePath) {
384
// public String displayName(String filePath) {
386
// return getInstanceCookie(filePath).instanceName();
387
// } catch (Exception e) {
388
// LOG.log(Level.WARNING, "Can't determine instance name from '" + filePath + "'", e); //NOI18N
389
// return DeadMarker.class.getName();
393
// public Object convert(String filePath) {
395
// return getInstanceCookie(filePath).instanceCreate();
396
// } catch (Exception e) {
397
// LOG.log(Level.WARNING, "Can't create instance from '" + filePath + "'", e); //NOI18N
398
// return DeadMarker.THIS;
402
// private InstanceCookie getInstanceCookie(String filePath) throws IOException {
403
// FileObject file = Repository.getDefault().getDefaultFileSystem().findResource(filePath);
404
// if (file == null) {
405
// // Should not occure
406
// throw new IOException("The file does not exist '" + filePath + "'"); //NOI18N
409
// DataObject d = DataObject.find(file);
410
// InstanceCookie cookie = d.getCookie(InstanceCookie.class);
411
// if (cookie != null) {
414
// // Should not occure
415
// throw new IOException("Can't find InstanceCookie for '" + filePath + "'"); //NOI18N
418
// } // End of InstanceConvertor class
420
// private static final class DeadMarker {
421
// public static final DeadMarker THIS = new DeadMarker();
422
// } // End of DeadMarker class