alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */


package org.openide.loaders;


import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.openide.cookies.InstanceCookie;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.util.Lookup;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.ProxyLookup;
import org.openide.util.Task;


/** Implements a lookup, that scans a content of a folder for its
 * data objects and asks them for instance cookie, the created objects
 * are then used to for the content of the lookup.
 * 

Any instances which are in fact instances of Lookup * will be proxied to, permitting one file to generate many instances * in the lookup system easily. * @author Jaroslav Tulach * @since 1.11 */ public class FolderLookup extends FolderInstance { /** Lock for initiliazation of lookup. */ private static final Object LOCK = new Object (); /** Lookup to delegate to. */ private ProxyLkp lookup; /** The root name of the lookup. */ private String rootName; /** Indicates whether this FolderLookup is at the root of (folder)tree which * we are interested in and the one which collects all items from the tree. */ private final boolean isRoot; /** Constructs the FolderLookup for given container. A default ID prefix is * used for identification of located items. * * @param df container (or folder) to work on */ public FolderLookup (DataObject.Container df) { this (df, "FL["); // NOI18N } /** Constructs the FolderLookup for given container. * @param df container (or folder) to work on * @param prefix the prefix to use */ public FolderLookup (DataObject.Container df, String prefix) { this(df, prefix, true); } /** Constructs the FolderLookup for given container. * @param df container (or folder) to work on * @param prefix the prefix to use * @param isRoot indicates whether this instance is the at the root of tree * in which we perform the lookup -> only this instance has lookup * which collects all items from the tree */ private FolderLookup(DataObject.Container df, String prefix, boolean isRoot) { super(df); this.rootName = prefix; this.isRoot = isRoot; } /** The correct class that this folder recognizes. * @return Proxy.Lkp class. */ public final Class instanceClass () { return ProxyLkp.class; } /** * Getter for the lookup that should be used. *

Serializable since 3.27. * @return a lookup */ public final Lookup getLookup () { boolean inited = false; synchronized(LOCK) { if(lookup == null) { lookup = new ProxyLkp(this); inited = true; } } if(inited) { checkRecreate(); } return lookup; } /** Updates the content of the lookup. * @param cookies updated array of instance cookies for the folder * @return object to represent these cookies * * @exception IOException an I/O error occured * @exception ClassNotFoundException a class has not been found */ protected final Object createInstance(InstanceCookie[] cookies) throws IOException, ClassNotFoundException { FolderLookupData flData = new FolderLookupData(); // If we are root, preserve place for abstract lookup which collects items. // see ProxyLkp.update method. if(isRoot) { flData.lookups.add(null); } for (int i = 0; i < cookies.length; i++) { try { // It's either result from underlying lookup or some another lookup or it is ICItem. Object obj = cookies[i].instanceCreate (); if(obj instanceof FolderLookupData) { // It's from underlying 'sub'-lookup. flData.items.addAll(((FolderLookupData)obj).items); flData.lookups.addAll(((FolderLookupData)obj).lookups); } else if(obj instanceof Lookup) { flData.lookups.add(obj); } else { // Has to be ICItem. flData.items.add(obj); } } catch(IOException ex) { exception(ex); } catch(ClassNotFoundException ex) { exception(ex); } } // If this is not the root lookup just return items+lookups // which will be collected by root lookup. if(!isRoot) { return flData; } // We are root FolderLookup. Now collect all items from underlying world. // Initializes lookup. getLookup(); lookup.update(flData.items, flData.lookups); return lookup; } /** Overrides superclass method. It returns instance * for DataObject&InstanceCookie 'pair'. * If the instance is of FolderLookup.Lkp class it is created otherwise * new Lkp.ICItem created and returned. * * @param dobj the data object that is the source of the cookie * @param cookie the instance cookie to read the instance from * @exception IOException when there I/O error * @exception ClassNotFoundException if the class cannot be found */ protected Object instanceForCookie(DataObject dobj, InstanceCookie cookie) throws IOException, ClassNotFoundException { boolean isLookup; if(cookie instanceof InstanceCookie.Of) { isLookup = ((InstanceCookie.Of)cookie).instanceOf(Lookup.class); } else { isLookup = Lookup.class.isAssignableFrom(cookie.instanceClass ()); } if(isLookup) { // Is underlying FolderLookup create it. return cookie.instanceCreate(); } else { return new ICItem(dobj, rootName, cookie); } } /** Folder is recognized as underlying FolderLookup which passes * its items to parent FolderLookup. * @param df the folder found * @return new FolderLookup */ protected InstanceCookie acceptFolder (DataFolder df) { return new FolderLookup(df, objectName(rootName, df), false); } /** Container is recognized as underlying FolderLookup which passes * its items to parent FolderLookup. * @param df the container found * @return new FolderLookup */ protected InstanceCookie acceptContainer (DataObject.Container df) { return new FolderLookup( df, rootName == null ? "" : rootName + "", // NOI18N false ); } /** Starts the creation of the object in the Folder recognizer thread. * Doing all the lookup stuff in one thread should prevent deadlocks, * but because we call unknown data loaders, they obviously must be * implemented in correct way. * * @param run runable to start * @return null, because the runnable is started immediatelly */ protected final Task postCreationTask (Runnable run) { run.run (); return null; } /** Concatenates name of folder with name of object. Helper method. * @param folderName name of folder or null * @param obj object to concatenate * @return new name */ private static String objectName (String name, DataObject obj) { if (name == null) { return obj.getName (); } else { return name + '/' + obj.getName (); } } /** Notifies the exception. Helper method. */ private static void exception (Exception e) { ErrorManager.getDefault ().notify (ErrorManager.INFORMATIONAL, e); } private static void exception(Exception e, FileObject fo) { ErrorManager.getDefault().annotate(e, ErrorManager.UNKNOWN, "Bad file: " + fo, null, null, null); // NOI18N exception(e); } /** ProxyLookup delegate so we can change the lookups on fly. */ static final class ProxyLkp extends ProxyLookup implements Serializable { private static final long serialVersionUID = 1L; /** FolderLookup we are associated with. */ private transient FolderLookup fl; /** Content to control the abstract lookup. */ private transient AbstractLookup.Content content; private transient boolean readFromStream; /** Constructs lookup which holds all items+lookups from underlying world. * @param folder FolderLookup to associate to */ public ProxyLkp(FolderLookup folder) { this(folder, new AbstractLookup.Content()); } /** Constructs lookup. */ private ProxyLkp(FolderLookup folder, AbstractLookup.Content content) { super(new Lookup[] {new AbstractLookup(content)}); this.fl = folder; this.content = content; } public String toString() { return "FolderLookup.lookup[\"" + fl.rootName + "\"]"; } private void writeObject (ObjectOutputStream oos) throws IOException { Lookup[] ls = getLookups(); for (int i = 0; i < ls.length; i++) { oos.writeObject(ls[i]); } oos.writeObject(null); oos.writeObject (fl.folder); oos.writeObject (fl.rootName); oos.writeObject (content); } private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException { List ls = new ArrayList(); // List Lookup l; while ((l = (Lookup)ois.readObject()) != null) { ls.add(l); } Lookup[] arr = (Lookup[])ls.toArray(new Lookup[ls.size()]); DataFolder df = (DataFolder)ois.readObject (); String root = (String)ois.readObject (); fl = new FolderLookup (df, root, true); fl.lookup = this; content = (AbstractLookup.Content)ois.readObject (); setLookups (arr); readFromStream = true; org.openide.util.RequestProcessor.getDefault ().post (fl, 0, Thread.MIN_PRIORITY); } /** Updates internal data. * @param items Items to assign to all pairs * @param lookups delegates to delegate to (first item is null) */ public void update(Collection items, List lookups) { readFromStream = false; // remember the instance lookup Lookup pairs = getLookups ()[0]; // changes the its content content.setPairs (items); if (fl.err().isLoggable(ErrorManager.INFORMATIONAL)) fl.err ().log ("Changed pairs: " + items); // NOI18N lookups.set(0, pairs); Lookup[] arr = (Lookup[])lookups.toArray (new Lookup[lookups.size ()]); setLookups (arr); if (fl.err().isLoggable(ErrorManager.INFORMATIONAL)) fl.err ().log ("Changed lookups: " + lookups); // NOI18N } /** Waits before the processing of changes is finished. */ protected void beforeLookup (Template template) { if (readFromStream) { // ok return; } // do not wait in folder recognizer, but in all other cases if (!FolderList.isFolderRecognizerThread ()) { fl.instanceFinished (); } } /** Mostly for testing purposes, to allow the tests to wait * for the scan to finished after deserialization. */ public void waitFinished () { fl.waitFinished (); } } // End of ProxyLkp class. /** Item that delegates to InstanceCookie. Item which * the internal lookup data structure is made from. */ private static final class ICItem extends AbstractLookup.Pair implements Serializable { static final long serialVersionUID = 10L; /** when deserialized only primary file is stored */ private FileObject fo; private transient InstanceCookie ic; /** source data object */ private transient DataObject obj; /** reference to created object */ private transient WeakReference ref; /** root folder */ private String rootName; /** Constructs new item. */ public ICItem (DataObject obj, String rootName, InstanceCookie ic) { this.ic = ic; this.obj = obj; this.rootName = rootName; this.fo = obj.getPrimaryFile(); } /** Initializes the item */ public void init () { if (ic != null) return; if (obj == null) { try { obj = DataObject.find(fo); } catch (DataObjectNotFoundException donfe) { ic = new BrokenInstance("File: " + fo.getPath(), donfe); // NOI18N return; } } ic = (InstanceCookie)obj.getCookie (InstanceCookie.class); if (ic == null) { ic = new BrokenInstance("File: " + fo.getPath(), null); // NOI18N } } /** * Fake instance cookie. * Used in case a file had an instance in a previous session but now does not * (or the data object could not even be created correctly). */ private static final class BrokenInstance implements InstanceCookie.Of { private final String message; private final Exception ex; public BrokenInstance(String message, Exception ex) { this.message = message; this.ex = ex; } public String instanceName() { return "java.lang.Object"; // NOI18N } private ClassNotFoundException die() { if (ex != null) { return new ClassNotFoundException(message, ex); } else { return new ClassNotFoundException(message); } } public Class instanceClass() throws IOException, ClassNotFoundException { throw die(); } public Object instanceCreate() throws IOException, ClassNotFoundException { throw die(); } public boolean instanceOf(Class type) { return false; } } /** The class of the result item. * @return the class of the item */ protected boolean instanceOf (Class clazz) { init (); if (ic instanceof InstanceCookie.Of) { // special handling for special cookies InstanceCookie.Of of = (InstanceCookie.Of)ic; return of.instanceOf (clazz); } // handling of normal instance cookies try { return clazz.isAssignableFrom (ic.instanceClass ()); } catch (ClassNotFoundException ex) { exception(ex, fo); } catch (IOException ex) { exception(ex, fo); } return false; } /** The class of the result item. * @return the instance of the object or null if it cannot be created */ public Object getInstance() { init (); try { Object obj = ic.instanceCreate(); ref = new WeakReference (obj); return obj; } catch (ClassNotFoundException ex) { exception(ex, fo); } catch (IOException ex) { exception(ex, fo); } return null; } /** Hash code is the InstanceCookie's code. */ public int hashCode () { init (); return System.identityHashCode (ic); } /** Two items are equal if they point to the same cookie. */ public boolean equals (Object obj) { if (obj instanceof ICItem) { ICItem i = (ICItem)obj; i.init (); init (); return ic == i.ic; } return false; } /** An identity of the item. * @return string representing the item, that can be used for * persistance purposes to locate the same item next time */ public String getId() { init (); if (obj == null) { // Deser problems. return ""; // NOI18N } return objectName(rootName, obj); } /** Display name is extracted from name of the objects node. */ public String getDisplayName () { init (); if (obj == null) { // Deser problems. return ""; // NOI18N } return obj.getNodeDelegate ().getDisplayName (); } /** Method that can test whether an instance of a class has been created * by this item. * * @param obj the instance * @return if the item has already create an instance and it is the same * as obj. */ protected boolean creatorOf(Object obj) { WeakReference w = ref; if (w != null && w.get () == obj) { return true; } if (this.obj instanceof InstanceDataObject) { return ((InstanceDataObject)this.obj).creatorOf (obj); } return false; } /** The class of this item. * @return the correct class */ public Class getType() { init (); try { return ic.instanceClass (); } catch (IOException ex) { // ok, no class available } catch (ClassNotFoundException ex) { // ok, no class available } return Object.class; } } // End of ICItem class. /** Data structure which holds ICItem's and Lookup's got * from current folder and underlying sub-folders making it possible to * pass to parent folder together. */ private static class FolderLookupData { /** Collection of ICItem's found in current * folder and its sub-folders. */ private Collection items; /** List of Lookup's found in current folder * and its sub-folders. */ private List lookups; /** Constructs data structure with inited fields. */ public FolderLookupData() { items = new ArrayList(30); lookups = new ArrayList(5); } } // End of FolderLookupData class. }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.