Dienstag, 4. Oktober 2011

ActionScript HTTPService - a common error - Error #1090

If your application is quite fine but someday you get an error like this: Error #1090: XML parser failure: element is malformed
Then you might have just missed to explicitly set the resultformat to something different than the default which is xml in Flex 4.5.

So the snippet with the fix in the last line is:
var service: HTTPService = new HTTPService();
service.url = url;
// note: default seems to be xml. XML seems to work for most cases but crashes for exmaple if a json response contains the character '<'
service.resultFormat = "text";



For the folks that thought as I did for the first time - here a short reminder: Flex does not care about the correctly set response type of your reponse. You have to set it manually as seen above.

Sonntag, 28. August 2011

Flash/Flex: Using Browser-Based Challenge-Response-Mechanisms for easy front-end to back-end communication

You have an application that needs authorization and you don't want to encode the credentials in the URL for each request. So why not delegate the authorization-stuff to the browser, your flash application is running in?
That article will show you one way to do that. It will also show up some pitfalls and important things to keep in mind.

Discussion

Is it better to transmit the credentials encoded in the URL or in the headers of the request being sent? Whats the advantage of browser based authentication instead of URL-encoded credentials?

So, first of all everybody of us should get the bad smell, if one wants to add credentials as part of the query-string of an URL. But why is it bad?

If you have no session that is checked for every request (which is normally true for REST-Applications and a lot of other scenarios) then anyone might copy and paste a URL-request into the address bar of a browser and you will receive the requested data without further authorization - sure, you have encoded the credentials in the URL itself... That might be very useful for testing and might ease your development. But the browser chronic and history might be a very interesting thing for malware that might cross your computer.
Ok, the proceeding point might not matter in a typical scenario. That is because the requests you are sending through the flash player will never leave the flash-player in a way that they might end up in the history.
But what if you someday want to interact with your browser in a different way: Maybe you want to request a resource that only authorized users should have access to. But you don't want that resource to be handled by the browser, instead of the flash player. One such scenario could be the desire to directly download and open a file with the default application that is set for that file type in the browser (Word or Excel for example).
How could that be achieved? You can easily add a hidden iframe to the embedding website and use JavaScript to re-point the src of the iframe to the resource (see http://hohenbichler.blogspot.com/2011/08/flashflex-load-resources-due-browser.html). The result will be the standard file-download-dialog of the browser and if the user wants so, the dialog is skipped and the file is directly opened with the correct application.
That is the point where you might get into trouble with the URL-encoded credentials: The URL is now leaving the flash-player and it is hold in JavaScript. That still might be no big issue. But maybe the associated program is saving the source-URL from where the file was get, or the download-history of your browser is saving the URL just for convenience as it always does (in Firefox right click on a downloaded file and choose copy download location). That might be a big security whole and your carefully setup https-connection is absolutely useless. It could get even worse: What if you are not absolutely ware of what you are logging on the server: Maybe you are running logging on info-level and that includes the requested URL for every request? For that case your highly secure LDAP-environment or your carefully salted user-credentials-db is absolutely useless because your logs contain all credentials of all your active users - What a mistake!

Now a technical reminder at that place: Also if you only see sth. like auth=32897shduiw= in your URL as part of the query-string, that is typically no encrypted user name and password. Most the time that is only a base-64 encoded string that could be decoded by everyone to clear-text user name + password. So encoded is not encrypted!


One way to use browser based authentication

At first we should clear our goals

  • We want a log-in dialog that works perfectly and is part of flash application.

  • We don't want an ugly browser-based authentication dialog.
    We don't want the credentials to be part of the URL and we want to prevent every situation where credentials could leak in into logs or some kind of client-sided history.

  • We want to have the option to request resources from our flex-application that should be handled by the browser.

  • we don't want to modify request-headers by ourselves.


  • Short illustration: Credentials in the headers (firebug)







    The solution

  • A flash-based log-in dialog that takes over the credentials (user name + password).




  • A simple JavaScript function that builds up a XMLHTTPRequest, takes user name + password and is blocking until the response arrives.




  • The flash/flex-application is checking the result of the JavaScript/browser based authentication and either shows up a "invalid credentials" message or logs the user in.




  • li>After the browser-based authentication is done, our application can forget about everything that has to do with authentication. The browser will transparently add the credentials to the http-request-headers every time.





    The interesting part: Code

    The JS-Part
    
    

    The AS-Part
    //note: the onAuthSuccess function will change the application-state to logged-in and the handleAuthError will get a error-string and display the message to the user
    private function doChallengeResponseAuthentication(onAuthSuccess:Function, handleAuthError:Function):void{
    	
    	if (!ExternalInterface.available){
    		throw new Error();
    	}
    	
    	// note: the request we are sending is synchronous, so we need no callback-stuff that might complicate the javascript-actionscript-interaction
    ExternalInterface.call("authenticate", user, password);
    		
    	const loginResponseStatus:String = ExternalInterface.call("getResponseStatus");
    	const loginResponseText:String = ExternalInterface.call("getResponseText");
    	trace("loginResponseStatus: " + loginResponseStatus);
    	trace("loginResponseText: " + loginResponseText);	
    	
    	if(loginResponseStatus == "" || loginResponseText == "" ){
    		throw new Error("Unable to read login response data from JS");
    	}			
    	
    	if(loginResponseStatus == "200"){
    		// our login also returns some JSON data that we decode here
    		onAuthSuccess(JSON.decode(loginResponseText));
    	} else if(loginResponseStatus == "403"){
    		handleAuthError("Login incorrect");
    	} else if(loginResponseStatus == "12029"){
    		handleAuthError("Server does not respond");
    	} else {
    		handleAuthError("Error: " + loginResponseStatus + " " + loginResponseStatus);
    	}
    	
    }
    


    Disable Rechellangeing

    You might need to change your server code to not re-challenge for the case of invalid credentials. If you don't do that you will get the ugly browser-based authentication popup in additon to you beautiful flash log-in dialog.

    If you are using restlet on server side you can disable re-challenging that way:

    ChallengeAuthenticator challengeGuard = new ChallengeAuthenticator(getContext(), ChallengeScheme.HTTP_BASIC, "Sample Service");
    challengeGuard.setVerifier(new CustomSecretVeryfier());
    challengeGuard.setRechallenging(false);
    


    Keep in mind

  • The most important thing is that our application still is "sniffable". Thatn means a bad guy that listens on our wire can capture all network-packages and extract the cretedntails - no matter if they are clear-text or base-64-encoded. That means you should really setup https if you have not done that, yet!




  • There is no common log-out function offered by the browser-APIs (only IE offers sth: document.execCommand("ClearAuthenticationCache");). The only cross-browser working way is to send invalid credentials and so destroy the current challenge-response-context.




  • Compared with URL-encoded credentials, one looses the ability to log in with different users multiple times in the same browser. That is because a browser only allows one open challenge-response-context.






  • Pitfalls

    I can't see the Authorization-Headers in my Debugging-/Networking perspective of the Internet Explorer


    Then you you should just open up Firefox and try firebug. Thats because IE just does not display that headers as you can see in the screenshots below:






    Getting JavaScript variables form the browser into your flex-application

    Here are big differences between the browsers:

    In Firefox (tested with FF6 and FF5): you can get whole complex JavaScript Objects form actionscript code. In other words you can ask for AuthContainer and you then could access all its properties over that. That does not sound interesting? Keep on reading and see how the IE works :-/
    In IE (tested with IE9): you could only get leaves of Objects. In other words: you can only get the property logged in of the Object AuthContainer. You cannot get the whole AuthContainer with all its properties. That makes programming a bit more ugly.

    So: You better write code on a common base and always use the ugly IE-way...



    Why use JavaScript for that? - I will modify the headers myself!

    You might think: Why not easily add the credential-stuff to each request I send through flash. That way I need no JavaScript interaction and the option to load resources directly through the browser is not relevant for me. If you are a flex expert than you might already know that flex does only allow header-modification on certain circumstances. The first obstacle is that get-request could not have user-modified headers - the flash-player will silently remove all changes. But you might have heard of a HTTP-Override-Header (TODO:Link to next Blog-Post) that needs server-sided support, but makes it possible to modify the headers of your http-requests. With that you really could get a working solution - just write the credentials in the right header-place and your server-code will see non difference to the chellenge-response made with XMLHTTPRequest. The problem that might appear later on is the following: When you combine browser-based authentication (automatically added credentials for each request by the browser) with the manually added http-header-credentials you will observe different behaviours in the different browsers. Today (August 2011) the following happens in IE8 and IE9: The credentials that you manually added to the request-headers are silently overwritten by the browser. In Firefox 6 you will get the following: The authorization-headers are appended (credentials are doubled under the same header key) and not replaced - that will mess up your authentication and your application is not usable any more. If you are running in IE. So in firefox you will immediately see a malbehaviour. But in the IE it could get even worse: Maybe you want use the cool "open directly with the correct application feature" only in some special part of your application. So thats the place wehere you implement the JavaScript-browser-authentication described above. If you do that you will get a mess: If you hit the reload-button of your browser and for that reason get a reloaded application with a showing up log-in dialog, you could login and everything seems to be fine. But, if you enter invalid credentials you will also be logged in - What the heck is happening? You are adding the wrong credentials manually to the headers but the browser is silently overwriting them with the still valid challenge-response, you have issued the last time you used the XMLHTTPRequest for authentication.
    So a final line-up: Never add credentials to headers by your own - It requires ugly workarounds to get it run and it might mess up your whole authentication-system and you will not immediately see that.

    Flash/Flex: Load resources due the browser and handle them with the current browser settings of the requested file-type (directly open, always save, …)

    Problem statement
    If you are running in your flash-context you have very limited options for file-handling: You can only open a file-download dialog where the user must select location and filename. There is no way as is in browser to always save and directly open the document of a specific type. It might annoy your users that they always have to manually locate the downloaded file and after that double click it.

    Solution
    Load the resources via the embedding website and an embedded iframe.

    If you have to to supply credentials for the requested resource and you currently transmit them encoded in the URL, you should read the following blog-article: TODO

    AS-Code
    public 
    function loadResourceViaBrowser(filename: String, loadViaBrowser:Boolean): void {
    
        if (!ExternalInterface.available){
           throw new Error();
        }
    
        var url:String = "http://localhost:8080/resource/someDocument.doc";
        ExternalInterface.call("loadResource", url);
    }
    


    JS/HTML-Code
    
    
        
    	
    		
    	
            
    		
            
        
    	
        	    
    	    
       
       
    
    

    Sonntag, 14. August 2011

    Preventing the Browser from caching a .swf-File (very useful in dev-mode)

    Relevant Snippet from the embedding html-template:

    // Note: appending the current time as query-parameter for the url
    // will prevent the internet explorer from caching the swf
    
    var currentDate = new Date();
    swfobject.embedSWF(
    "${swf}.swf?" + currentDate.getTime(), "flashContent",
    "${width}", "${height}",
    swfVersionStr, xiSwfUrlStr,
    flashvars, params, attributes);
    
    

    Notes:
    As you see the trick is to append the query-string with a random number, so the browser must assume the resource you are requesting is never the same.
    For production use you should consider to replace the current time with the version-number of the release.

    Change the Flash Builder IDE language

    Yes, this seems to be a stupid topic to blog about, but the eclipse based Flash Builder IDE does not offer an option to change the language. Also the Fllash Builder setup does not seem to take over the language selected at the setup, instead the OS-Language is used. Also there are a lot of misleading tips around in the internet that did not work for me.

    Windows (Tested With: Flash Builder 4.5)
    Open the link that you use to start Flash Builder (or create a new link). Add the option "-nl en_US" or whatever language you want to use:
    "C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.5\FlashBuilder.exe" -nl en_US

    MacOs (Tested With: Flash Builder 4.5)
    From the command line or in a Shell script:
    open ~/Applications/eclipse-jee-indigo-macosx-cocoa/Eclipse.app/ --args -nl en_US

    Freitag, 1. Mai 2009

    Common Navigator Framework (CNF)

    What is this document?

    This document wants to be an effective starting point for all Eclipse-RCP-developers new to the CNF.
    It provides you with a brief introduction of what it is and what it is useful for.
    It provides some sample code that could be found here. The aim of the sample code is to concentrate on how to use the CNF in RCP-Applications and how to contribute content to one CNF-based view from different plug-ins. All of the sample code sticks to the very basics and should only give you the core-idea of why it could be useful for you.
    For everything more advanced you should take a look on the further reading section, the sample code section and the real life example section.

    What is the CNF?

    In short: It is a view containing a special treeviewer that could be used in Eclipse based applications. The treeviewers degree of details is dynamically configurable via extensions. So one plug-in could create the initial view and a lot of other plugins can change the details that should be displayed.
    For example it solves the view-explosion-problem: A view is existing and displays some data. Now you find it usable to view some other details for the already displayed objects. Without the CNF you need to create a new view that duplicates the already visible data appended with the details you need. That “duplication” is at least needed, when the original code of the view could not be changed by you. Let’s say because the view is contributed by another plug-in, from another company.
    For more details take a look at the section “further reading”.

    A real life example – the Project Explorer

    The maybe most famous example is the Project Explorer View within the Eclipse IDE. You can open it’s plugin.xml easily due the "Plug-ins" View with a double-click on org.eclipse.ui.navigator.resources.


    Package Explorer View and Project Explorer View

    Another example is the Eclipse Web Tools Platform (WTP).
    Hints:
    • Some Contributions to the Project Explorer View can be found in the plugin.xml of the Plug-in org.eclipse.jdt.ui .
    • The definition of the Resources Perspective (which the Project Explorer belongs to) could be found in the Plug-in org.eclipse.ui.ide.application.
    Hints to prevent confusion:
    • The Package Explorer View within Eclipse is not based on the CNF, although some people name it as an example for the CNF.
    • The Project Explorer View is based on the CNF and provides nearly the same features as the Package Explorer View does. It seems that the Project Explorer View was intended to replace the Package Explorer View someday, but for now there are still pieces of code that only relay on the Package Explorer…

    Short history of CNF

    • Created by Michael Elder
    • Originally created for IBM Rational Application Developer (RAD)
    • CNF is new with Eclipse 3.2

    My cnfdemo sample code

    Tested with: Eclipse 3.4, Eclipse 3.5
    Is available for download here
    The aim of the sample code is to concentrate on how to use the CNF in RCP-Applications and how to contribute content to one CNF-based view from different plug-ins. All of the sample code sticks to the very basics and should only give you the core-idea of why it could be useful for you.
    The cnfdemo consists of 4 very small plugin-projects that you could easily import with the Import-Wizard of the Eclipse IDE. (File - Import - Existing Projects into Workspace)
    Hint:
    • The CNF-Plug-in (org.eclipse.ui.navigator) is not included in the RCP Target Platform. If you are just using the Eclipse installation as your Target Platform (which is the normal setup) you don’t need to care about that detail.
    The screenshots above give you an overview of which plug-in contributes what to the ui.

    cnfdemo: basisc plugin structure part 1

    cnfdemo: basisc plugin structure part 2

    cnfdemo.core – contains the application and the workbench. More interesting for CNF it also contains the plugin.xml configuration for the CNF-View. It also contains an interface that all Elements of the CNF-treeview should implement.
    cnfdemo.fruits – contains model-classes for fruits (bananas and apples). Via plugin.xml this plugin contributes to the CNF-based view and makes the new business-objects visible in the CNF-view. It contains a LabelProvider and a ContentProvider for the fruits.
    cnfdemo.geometric – same like cnfdemo.fruits just with some completely different business-objects (geometric forms).
    cnfdemo.details – adds a detailed LabelProvider and ContentProvider that makes some details visible for the already displayed business-objects. For apples it shows the weight, for rectangls it shows the length of the sides a and b.

    snippets: cnfdemo.core

    plugin.xml (cnfdemo.core)
       
          
          
       
       
          
             
                
                
             
          
       
       
          
          
          
             
                
                
             
          
       
    


    NavigatorRoot.java
    public class NavigatorRoot extends PlatformObject {
     
    	private List cnfTreeObjects = new LinkedList();
     
    	public NavigatorRoot(){
     
    		cnfTreeObjects.add(new ICnfTreeObject(){
     
    			@Override
    			public ICnfTreeObject getParent() {
    				return null;
    			}
     
    			@Override
    			public String getText() {
    				return "dummy - ICnfTreeObject";
    			}
    		});
    	}
     
    	public void addCnfTreeObject(ICnfTreeObject cnfTreeObject){
    		cnfTreeObjects.add(cnfTreeObject);
    	}
     
    	public List getCnfTreeObjects() {
    		return cnfTreeObjects;
    	}
     
    	public void addgetCnfTreeObject(ICnfTreeObject cnfTreeObject) {
    		cnfTreeObjects.add(cnfTreeObject);
    	}
     
    }
    


    ICnfTreeObject.java
    public interface ICnfTreeObject {
     
    	ICnfTreeObject getParent();
    	String getText();
     
    }
    


    ParentBeanContentProvider.java
    public class ParentBeanContentProvider implements ITreeContentProvider {
     
    	public Object[] getChildren(Object parentElement) {
    		if (parentElement instanceof NavigatorRoot) {
    			return ((NavigatorRoot) parentElement).getCnfTreeObjects().toArray();
    		}
    		return new Object[0];
    	}
     
    	public Object getParent(Object element) {
    		return null;
    	}
     
    	public boolean hasChildren(Object element) {
    		return this.getChildren(element).length > 0;
    	}
     
    	public Object[] getElements(Object inputElement) {
    		return this.getChildren(inputElement);
    	}
     
    	public void dispose() {
    	}
     
    	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    	}
    }
    


    ParentBeanLabelProvider.java
    public class ParentBeanLabelProvider implements ILabelProvider {
     
    	public Image getImage(Object element) {
    		return null;
    	}
     
    	public String getText(Object element) {
    		if (element instanceof ICnfTreeObject) {
    			return ((ICnfTreeObject) element).getText();
    		}
    		return new String();
    	}
     
    	public void addListener(ILabelProviderListener listener) {
    	}
     
    	public void dispose() {
    	}
     
    	public boolean isLabelProperty(Object element, String property) {
    		return false;
    	}
     
    	public void removeListener(ILabelProviderListener listener) {
    	}
    }
    

    snippets: cnfdemo.detail

    plugin.xml (cnfdemo.detail)
    
    
       
          
             
                
                   
                   
                   
                   
                   
                   
                   
                   
                
             ldren>
          
       
       
          
             
                
                
             
          
       
    
    


    DetailContentProvider.java
    public class DetailContentProvider implements ITreeContentProvider {
     
    	public Object[] getChildren(Object parentElement) {
    		if (parentElement instanceof Rectangle){
    			LinkedList linkedList = new LinkedList();
    			linkedList.add(new Detail((ICnfTreeObject) parentElement, "side a: " + new Integer(((Rectangle)parentElement).getA()).toString()));
    			linkedList.add(new Detail((ICnfTreeObject) parentElement, "side b: " + new Integer(((Rectangle)parentElement).getB()).toString()));
    			return linkedList.toArray();
    		}
    		if (parentElement instanceof Circle){
    			LinkedList linkedList = new LinkedList();
    			linkedList.add(new Detail((ICnfTreeObject) parentElement, "radius: " + new Integer(((Circle)parentElement).getRadius()).toString()));
    			return linkedList.toArray();
    		}
    		if (parentElement instanceof Apple){
    			LinkedList linkedList = new LinkedList();
    			linkedList.add(new Detail((ICnfTreeObject) parentElement, "weight: " + new Integer(((Apple)parentElement).getWeight()).toString()));
    			return linkedList.toArray();
    		}
    		if (parentElement instanceof Banana){
    			LinkedList linkedList = new LinkedList();
    			linkedList.add(new Detail((ICnfTreeObject) parentElement, "weight: " + new Integer(((Banana)parentElement).getWeight()).toString()));
    			return linkedList.toArray();
    		}
    		return new Object[0];
    	}
     
    	public Object getParent(Object element) {
    		if (element instanceof ICnfTreeObject)
    			return ((ICnfTreeObject)element).getParent();
    		return null;
    	}
     
    	public boolean hasChildren(Object element) {
    		return this.getChildren(element).length > 0;
    	}
     
    	public Object[] getElements(Object inputElement) {
    		return this.getChildren(inputElement);
    	}
     
    	public void dispose() {
    	}
     
    	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    	}
     
    }
    


    DetailLabelProvider.java
    public class DetailLabelProvider implements ILabelProvider {
     
    	public Image getImage(Object element) {
    		return null;
    	}
     
    	public String getText(Object element) {
    		if (element instanceof Detail) {
    			return ((Detail) element).getText();
    		}
    		return new String();
    	}
     
    	public void addListener(ILabelProviderListener listener) {
    	}
     
    	public void dispose() {
    	}
     
    	public boolean isLabelProperty(Object element, String property) {
    		return false;
    	}
     
    	public void removeListener(ILabelProviderListener listener) {
    	}
    }
    



    Avanced Topic: Override existing Content-Contributions

    With the CNF it is possible to replace content that has already been contributed by another plugin, with some content we consider more valuable. cnfdemo.volume – this plug-in uses the possibility provided by the CNF to override existing content-contributions. It removes the sides a and b that are displayed so far due the cnfdemo.details-plug-in and adds the volume instead.



    cnfdemo: the former displayed sides a and b of the rectangle are overwritten with the volume


    relevant code-snippets

    plugin.xml (cnfdemo.volume)
    
    
    
       
          
             
                
                
             
          
       
       
          
             
                
                
             
             
             
          
       
    
    



    VolumeContentProvider.java
    public class VolumeContentProvider implements IPipelinedTreeContentProvider {
     
    	@Override
    	public Object[] getChildren(Object parentElement) {
    		System.out.println("VolumeContentProvider.getChildren() - parentElement.getClass(): " + parentElement.getClass());
    		if (parentElement instanceof Rectangle) {
    			LinkedList linkedList = new LinkedList();
    			linkedList.add(new Volume((ICnfTreeObject) parentElement, "volume: "
    					+ new Integer(((Rectangle) parentElement).getA() * ((Rectangle) parentElement).getB()).toString()));
    			return linkedList.toArray();
    		}
    		 return new Object[0];
    	}
     
    	public Object getParent(Object element) {
    		if (element instanceof ICnfTreeObject)
    			return ((ICnfTreeObject) element).getParent();
    		return null;
    	}
     
    	public boolean hasChildren(Object element) {
    		return this.getChildren(element).length > 0;
    	}
     
    	public Object[] getElements(Object inputElement) {
    		return this.getChildren(inputElement);
    	}
     
    	@Override
    	public void getPipelinedChildren(Object aParent, Set theCurrentChildren) {
     
    		// When this method is called theCurrentChildren are instances
    		// of Detail.
    		// We replace that with instances of Volume.
    		//       
    		// GUI representation without doing the replacement:
    		//   side a: 10
    		//   side b: 20
    		//        
    		// GUI representation after doing the replacement:
    		//   volume: 200
     
    		theCurrentChildren.clear();
     
    		Object[] children = getChildren(aParent);
    		for (int i = 0; i < children.length; i++) {
    			theCurrentChildren.add(children[i]);
    		}
    	}
    	…
    }
    


    VolumeLabelProvider.java
    public class VolumeLabelProvider implements ILabelProvider {
    	@Override
    	public String getText(Object element) {
    		if (element instanceof Volume) {
    			return ((Volume) element).getText();
    		}
    		return null;
    	}
    …
    }
    
    
    
    Sample code for education (created by other people)

    Advanced sample code

    Advanced sample code also demonstration how to use filters, contribute actions and more. It is the sample-code that belongs to Michael Elders tutorial series on CNF that could be found here: http://scribbledideas.blogspot.com/2006/07/pdf-versions-now-available.html CVS-Connection for "Paste Connection" in the CVS View: pserver:anonymous@dev.eclipse.org:/cvsroot/eclipse Project: org.eclipse.ui.examples.navigator

    Basic sample code – using CNF in RCP

    Very basic example, describing how to use CNF within RCP. On the site http://rcpquickstart.com/2007/04/25/common-navigator-tutorial-1-hello-world/ click on the link "Eclipse 3.3" on the bottom of the article.

    CNF and the Rich Ajax Platform (RAP)

    A short porting-try made the general problems visible that could happen when porting an RCP-Application to an RAP-Application. The CNF plugin has some dependencies on code that is only available in the rcp-version of the ui-plugin (org.eclipse.ui) and not in the rap-verions (org.eclipse.rap.ui). Maybe the following citation also gives a direction for the nearest future of CNF with RAP. Citation (Mon, 23 Jun 2008): http://dev.eclipse.org/newslists/news.eclipse.technology.rap/msg03575.html Hi, sorry to say so, but currently there are no plans for providing the Common Navigator Framework in RAP. Ciao Frank

    Some clearance about triggerPoints and possibleChildren

    Citation 1 http://scribbledideas.blogspot.com/2006/06/what-does-common-navigator-framework.html In general, if you contribute something, then that thing is a possible child; if you can provide children for something, then that thing is a trigger point. Often, most things that are trigger points are also possible children, but this is not always the case. For instance, many WTP extensions specify trigger points as IProjects with specific facets, but they never contribute these types of things to the viewer; they simple augment them with new types of children. You want to identify all of your model elements as trigger points and possible children; then add to the trigger points the nodes that you begin growing from the tree. In this case, this may be the root node of your model. Citation 2 http://dev.eclipse.org/blogs/francis/2009/01/15/community-comments-needed-for-common-navigator-label-providers/ A secondary problem is that the current documentation is bad: The current documentation for the NCE states that: The triggerPoints expression describes the elements that will cause this extension to be invoked for either children or for labels. The possibleChildren expression describes the elements that the extension may be able to provide a parent for. Clients should describe all elements that could be set as the selection to ensure that the link with editor support can properly expand to the right node. … and … A navigator content extension defines a content provider and label provider that can be used to provide children whenever an element matches the triggerPoints expression and also to provide a parent whenever an element matches the possibleChildren expression. The above statements are not correct with respect to label providers. Label providers use the possibleChildren expression, not triggerPoints expression. The documentation will be corrected to match the current behavior, since changing the behavior to match the documentation could break many things.

    Further reading

    Documentation in the Eclipse Help http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/cnf.htm Digital Paper Napkin - Sample Code and tutorials from the CNF-Author http://scribbledideas.blogspot.com/ What does the Common Navigator Framework (CNF) help me do? http://scribbledideas.blogspot.com/2006/06/what-does-common-navigator-framework.html Common Navigator Tutorial 1: Hello World http://rcpquickstart.com/2007/04/25/common-navigator-tutorial-1-hello-world/ New in Eclipse 3.5: An Extension-Wizard for a Common Navigator http://swik.net/Eclipse/Eclipse+Tips/Easiest+way+to+create+a+Common+Navigator/cp0zx Newsgroup http://dev.eclipse.org/newslists/news.eclipse.technology.rap/ Common Navigator Framework Use Cases – Discussion for next Eclipse release (3.5) http://wiki.eclipse.org/Common_Navigator_Framework_Use_Cases Displaying Non-Resource Content Using the Common Navigator Framework http://aashishpatil.blogspot.com/2006/07/displaying-non-resource-content-using.html Common Navigator and Other Things – Blog http://dev.eclipse.org/blogs/francis/