|
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.netbeans.modules.xml.tree.completion;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.LinkedList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import org.netbeans.tax.*;
import org.netbeans.tax.dom.Wrapper;
import org.netbeans.spi.xml.cookies.DataObjectAdapters;
import org.netbeans.modules.xml.core.XMLDataObject;
import org.netbeans.modules.xml.api.model.GrammarEnvironment;
import org.netbeans.modules.xml.api.model.GrammarQuery;
import org.netbeans.modules.xml.api.model.GrammarQueryManager;
import org.netbeans.modules.xml.spi.model.EmptyQuery;
import org.netbeans.modules.xml.tax.cookies.TreeEditorCookie;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.util.RequestProcessor;
import org.openide.util.Task;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.openide.awt.StatusDisplayer;
/**
* Manages grammar to tree editor association.
*
* Mostly copied from the xml-text editor's version, but
* this one cannot dynamically update.
*
* @author Rich Unger
*/
public class GrammarManager {
// maintain a map of DataObject --> Grammar
private static HashMap s_map = new HashMap();
// last invalidation time
private long timestamp = System.currentTimeMillis();
private int delay = 0;
// current cache state
private int state = INVALID;
static final int VALID = 1;
static final int LOADING = 2;
static final int INVALID = 3;
// cache entry
private GrammarQuery grammar;
// noop loader
private static final RequestProcessor.Task EMPTY_LOADER =
RequestProcessor.createRequest(Task.EMPTY);
// current loader
private RequestProcessor.Task loader = EMPTY_LOADER;
// grammar is provided for this document
private final XMLDataObject dObj;
public static GrammarQuery getGrammar( XMLDataObject d )
{
if (d == null) throw new IllegalArgumentException("null"); // NOI18N
synchronized( s_map )
{
GrammarManager mgr = (GrammarManager)s_map.get(d);
if( mgr == null )
{
mgr = new GrammarManager(d);
s_map.put(d, mgr);
}
return mgr.getGrammar(1000);
}
}
/**
* Create new manager.
*/
public GrammarManager(XMLDataObject dObj) {
if (dObj == null) throw new IllegalArgumentException("null"); // NOI18N
this.dObj = dObj;
}
/**
* Return any suitable grammar that you can get
* till expires given timeout.
*/
public synchronized GrammarQuery getGrammar(int timeout) {
switch (state) {
case VALID:
return grammar;
case INVALID:
state = LOADING;
loadGrammar(); // async
case LOADING:
waitLoaded(timeout); // possible thread switch !!!
//??? return last loaded grammar (use option?)
if (grammar != null) return grammar;
default:
return EmptyQuery.INSTANCE;
}
}
/**
* Nofification from grammar loader thread, new valid grammar.
* @param grammar grammar or null if cannot load.
*/
private synchronized void grammarLoaded(Task loader, GrammarQuery grammar) {
try {
// eliminate zombie loader
if (this.loader != loader) return;
String status = (grammar != null) ? Util.THIS.getString("MSG_loading_done")
: Util.THIS.getString("MSG_loading_failed");
this.grammar = grammar == null ? EmptyQuery.INSTANCE : grammar;
state = VALID;
notifyProgress(loader, status);
} finally {
notifyAll();
}
}
/**
* Notify loader progress filtering out messages from zombies
*/
private void notifyProgress(Task loader, String msg) {
if (this.loader != loader) return;
StatusDisplayer.getDefault().setStatusText(msg);
}
/**
* Async grammar fetching
*/
private void loadGrammar() {
class LoaderTask extends Task {
// my represenetation in RQ as others see it
private RequestProcessor.Task self;
public void run() {
GrammarQuery loaded = null;
try {
String status = Util.THIS.getString("MSG_loading");
notifyProgress(self, status);
GrammarQueryManager gqm = GrammarQueryManager.getDefault();
InputSource inputSource = DataObjectAdapters.inputSource(dObj);
FileObject fObj = dObj.getPrimaryFile();
// get the document children
TreeDocumentRoot docRoot = null;
try {
TreeDocumentRoot result;
TreeEditorCookie cake = (TreeEditorCookie) dObj.getCookie(TreeEditorCookie.class);
if (cake != null) {
result = cake.openDocumentRoot();
} else {
throw new TreeException("XMLDataObject:INTERNAL ERROR"); // NOI18N
}
docRoot = result;
}
catch( Exception ex ) {
return;
}
Iterator treeObjectIter = docRoot.getChildNodes().iterator();
LinkedList ctx = new LinkedList ();
while( treeObjectIter.hasNext() )
{
TreeObject child = (TreeObject)treeObjectIter.next();
try {
ctx.add ( Wrapper.wrap(child) );
}
catch( RuntimeException ex ) {
System.err.println("Could not wrap TAX object: "
+ child.getClass().getName());
}
}
GrammarEnvironment env = new GrammarEnvironment(Collections.enumeration (ctx), inputSource, fObj);
if( gqm.enabled(env) != null )
{
loaded = gqm.getGrammar(env);
}
} finally {
grammarLoaded(self, loaded);
notifyFinished();
}
}
}
// we need a fresh thread per loader (some requests may block)
RequestProcessor rp = RequestProcessor.getDefault();
LoaderTask task = new LoaderTask();
loader = rp.create(task);
task.self = loader;
// do not allow too many loaders if just editing invalidation area
loader.schedule(delay);
}
/**
* Wait till grammar is loaded or given timeout expires
*/
private void waitLoaded(int timeout) {
try {
if (state == LOADING) wait(timeout);
} catch (InterruptedException ex) {
}
}
}
|