You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xap-commits@incubator.apache.org by jm...@apache.org on 2006/06/22 22:59:36 UTC

svn commit: r416494 - in /incubator/xap/trunk: src/xap/ src/xap/taghandling/ testsrc/ testsrc/xap/taghandling/

Author: jmargaris
Date: Thu Jun 22 15:59:35 2006
New Revision: 416494

URL: http://svn.apache.org/viewvc?rev=416494&view=rev
Log:
having a subdirectory called "tags" was a bad idea

Added:
    incubator/xap/trunk/src/xap/taghandling/
    incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js   (with props)
    incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js   (with props)
    incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js   (with props)
    incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js   (with props)
    incubator/xap/trunk/src/xap/taghandling/plugin.xml   (with props)
    incubator/xap/trunk/testsrc/xap/taghandling/
    incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html   (with props)
    incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html   (with props)
    incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html   (with props)
    incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js   (with props)
    incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html   (with props)
    incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml   (with props)
Modified:
    incubator/xap/trunk/src/xap/Xap.js
    incubator/xap/trunk/testsrc/XapUnitTestSuite.html

Modified: incubator/xap/trunk/src/xap/Xap.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/Xap.js?rev=416494&r1=416493&r2=416494&view=diff
==============================================================================
--- incubator/xap/trunk/src/xap/Xap.js (original)
+++ incubator/xap/trunk/src/xap/Xap.js Thu Jun 22 15:59:35 2006
@@ -135,9 +135,9 @@
         
 
 	//xap.tags (TODO rename?_
-	Utils.importFile(  sourceRootDir + "/src/xap/tags/AbstractTagImpl.js" );
-	Utils.importFile(  sourceRootDir + "/src/xap/tags/PluginDocumentHandler.js" );
-	Utils.importFile(  sourceRootDir + "/src/xap/tags/PluginRegistryImpl.js" );
+	Utils.importFile(  sourceRootDir + "/src/xap/taghandling/AbstractTagImpl.js" );
+	Utils.importFile(  sourceRootDir + "/src/xap/taghandling/PluginDocumentHandler.js" );
+	Utils.importFile(  sourceRootDir + "/src/xap/taghandling/PluginRegistryImpl.js" );
     
 
 

Added: incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js (added)
+++ incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,747 @@
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+//TODO we need to handle qualifying URLs properly based on the request page again
+ 
+/**
+ * @fileoverview The base class for all element to peer object
+ * bridges. 
+ * 
+ * @author ikaplansky
+ * @author jmargaris
+ */
+ 
+/**
+ * Creates a new AbstractTagImpl, this is typically called by the parsing
+ * framework and should not be called directly by other code.
+ * 
+ * @class The base class for all user-defined tag-handling classes.
+ * <br><br>
+ * 
+ * Whenever a new document fragment is added to the UI document, the following 
+ * steps take place:
+ * <ol>
+ * <li>The name of the root tag is looked up in the default and any extra
+ * tag-mapping files to find the class that is supposed to that handle that tag.
+ * If no class is found that is the end of the process.</li>
+ * <li>Assuming the class exists, a member of that class is constructed via
+ * a no-arg constructor.</li>
+ * <li>The handling instance (AKA the tag-handler) and the element are added
+ * to hashtables so that one can be looked up from the other.</li>
+ * <li>The tag-handler setSession() method is called so that it can access the session.
+ * It is <b>not</b> added to the application as an MCO.</li>
+ * <li>The tag-handler is added to the Element as an
+ * AttributeChangeListener and a StructureChangeListener.</li>
+ * <li>setElement() is called with the XML element that is mapped to the tag-handler.</li>
+ * <li>Finally, init() is called.</li>
+ * </ol>
+ * 
+ * It is important to understand that when a document fragment is added to the
+ * UI document that fragment may have a number of descendents. Those descendents
+ * do <b>not</b> automatically go through the same process. However, 
+ * this class provides parseInitialChildren() to mimic recursive parsing of the children.
+ * Similarly, an Element can be added to the UI document with attributes already in place.
+ * Those initial attributes will not create attributeChange events. However, this
+ * class provides parseInitialAttributes() to help processing in that case.
+ * 
+ * <br><br>
+ * To respond correctly to dynamic changes in the document, a tag handler
+ * should respond to AttributeChangeEvents and StructureChangeEvents in a suitable
+ * fashion.
+ * <br><br>
+ * It is possible for a single tag-handler to handle an entire subtree of 
+ * elements. In this case the tag-handler can add itself as an AttributeChangeListener
+ * and/or StructureChangeListener on each element in the controlled subtree.
+ * 
+ * @author ikaplansky
+ * @author jmargaris
+ */
+
+function AbstractTagImpl() {
+	this._element = null;
+	this._peer = null;
+	this._clientSession = null;
+}
+
+//-----------------------------------------------------------------------
+// Public Methods.
+//-----------------------------------------------------------------------
+
+
+/**
+ * Returns the element this tag mapped to.
+ */
+AbstractTagImpl.prototype.getElement = function() {
+	return this._element;
+}
+
+/**
+ * Sets the element this tag maps to, this is called during the
+ * automatic intiliazation process.
+ * 
+ * @param e The element this tag maps to.
+ */
+AbstractTagImpl.prototype.setElement = function( el ) {
+	this._element = el;
+}
+
+/**
+ * Returns the object that this bridge controls.
+ */
+AbstractTagImpl.prototype.getPeer = function() {
+	return this._peer;
+}
+
+/**
+ * Subclasses should override this method to provide proper initialization
+ * behavior. This is the final call in the tag-handler creation process.
+ */
+AbstractTagImpl.prototype.init = function() {}
+
+
+//-----------------------------------------------------------------------
+// Protected Methods.
+//-----------------------------------------------------------------------
+
+/**
+ * Sets the object that this bridge controls.To use
+ * <code>UiContentHandler.getHandlerForPeer()</code> it is not enough
+ * to call this method, the developer must also call
+ * <code>UiContentHandler.setHandlerForPeer()</code>. This call is made 
+ * automatically in ContainerBridge but classes that extend AbstractTagImpl 
+ * directly must call them themselves if they need the ability to do the peer 
+ * to handler lookup.
+ */
+AbstractTagImpl.prototype.setPeer = function( obj ){
+	this._peer = obj;
+	this.getUiContentHandler().setHandlerForPeer( obj, this);
+}
+
+/**
+ * @return The UI document
+ */
+AbstractTagImpl.prototype.getUiDocument = function() {
+	return this.getSession().getDocumentContainer().getUiDocument();
+}
+
+/**
+ * This method is provided for convenience to deal with elements
+ * that start with a number of attributes when they are added to the 
+ * document. This method will run through all the initial attributes
+ * and construct an AttributeChangeEvent for each attribute, then
+ * call onAttributeSet with that change event. This simulates
+ * an element that was added with no attributes and then had attributes
+ * added at a later point.
+ * <br><br>
+ * This method takes an element to handle the case where one
+ * tag handler handles multiple tags. In most normal applications
+ * this element will be the result of getElement()
+ * 
+ * @param e The element to parse the initial attributes from.
+ */
+AbstractTagImpl.prototype.parseInitialAttributes = function( e ) {
+	var attributes = e.attributes;
+	
+	var names = new Array(attributes.length);
+
+	//have to copy them over, because as we add attributes the enumeration
+	//itself changes. This is a problem if adding an attribute causes
+	//more attributes to be added, which can happen with class when
+	//the stylesheet attributes are added, and we get tricked into
+	//thinking they are not from the stylesheet. Instead, we think
+	//they were an initial attribute since they were tacked on to the
+	//enumeration
+	
+	for (var i = 0; i<attributes.length; i++){
+		var attributeName = e.attributes[i].nodeName;
+		names[i] = attributeName;
+	}
+	
+	for ( var i=0; i < names.length; i++ ) {
+		var attributeName = names[i];
+		var attributeValue = e.getAttribute( attributeName );
+		var event = new AttributeChangeEvent( e, attributeName, attributeValue );
+		// change the value
+		this.beforeAttributeSet( event );
+		this.onAttributeSet( event );
+	}
+}
+
+/**
+ * This method is provided for convenience to deal with elements
+ * that start with a number of children when they are added to the 
+ * document. For each initial child, this method will call
+ * UiContentHandler.parseChild() on that child element, which initiates
+ * the tag-handling steps defined above. After calling parseChild() on a
+ * child element a StructureChangeEvent is created and sent to onChildAdded().
+ * This simulates
+ * an element that was added with no children and then had children
+ * added at a later point.
+ * <br><br>
+ * This method takes an element to handle the case where one
+ * tag handler handles multiple tags. In most normal applications
+ * this element will be the result of getElement()
+ * 
+ * @param e The element to parse the initial children of.
+ */	
+AbstractTagImpl.prototype.parseInitialChildren = function( e ) {
+	var session = this.getSession();
+	var contentHandler = session.getUiDocumentHandler();
+	
+	var children = new Array(e.childNodes.length);
+	for ( var i = 0; i<children.length; i++){
+		children[i] = e.childNodes[i];
+	}
+	//TODO we need this for iterator but we really need a more efficient
+	//way to do this
+	for ( var i = 0; i < children.length; i++ ) {
+		var child = children[i];
+		if ( child.nodeType==DOM_ELEMENT_NODE ) {
+			contentHandler.parseChild( child );
+		
+			//-1 index means an append, even though we already have
+			//all the child elements we want to pretend we are adding
+			//them right now, so just fire off each one as if it was appended
+			var event = new StructureChangeEvent( e, child, -1 );
+			this.beforeChildAdded( event );
+			this.onChildAdded( event );
+		}
+		if ( child.nodeType==DOM_TEXT_NODE ) {
+			//TODO this needs some work in that they are supposed to be able
+			//to CHANGE the text in the beforeChildAdded and that is supposed to
+			//be what we actually add. This can happen with databinding syntax
+			//where the text is replaced with filled-in values. What we really
+			//need to do here is fire the before, then if the new value is different
+			//from the old actually REPLACE the old text value with the new one.
+			//for reference the old code looked like:
+			// writeBackRemoveChild(i);
+			//	e.insertChildAt(i,(String)o);
+			//This worked but was somewhat inneficient in that it always removed
+			//and re-added the text node. Perhaps in this case what we should do
+			//is instead of actually change the text node just change the VALUE
+			//of the text node instead. So if we see a text node with data binding like:
+			// <button>{ someOtherButton.text }</button>
+			//we replace the someOtherButton.text with the resolved value by changing
+			//the value of the text node while keeping the same text node overall.
+			
+			var event = new StructureChangeEvent( e, child, -1 );
+			this.beforeChildAdded( event );
+			this.onChildAdded( event );
+		
+		}
+	}
+}
+
+
+/**
+ * Returns the URL context for the current thread. The URL context can be
+ * used to translate relative URLs into non-relative URLs. For example,
+ * if the page MYAPP/pages/myPage.jsp contains onCommand="pages2/anotherPage.xml",
+ * the URL context is "MYAPP/pages/" and the onCommand should refer to
+ * "MYAPP/pages/pages2/anotherPage.xml"
+ * 
+ * @return The URL context of the current thread, which can be null.
+ */
+AbstractTagImpl.prototype.getUrlContext = function() {
+	return this.getSession().getUrlContext();
+}
+
+///**
+// * Turns a potentially relative URL into a fully qualified one.
+// * If this is called from the parsing thread during the parsing of a page,
+// * the url is qualified relative to that page's origin. Otherwise the 
+// * url should begin with http:/, https:// or "/"
+// * @param relativeUrl The URL to qualify.
+// * @return A fully qualified URL.
+// * @throws MalformedURLException
+// */
+//AbstractTagImpl.prototype.createQualifiedUrl = function( relativeUrl ) {
+//	var urlContext = this.getUrlContext();
+//	if ( urlContext != null ) {
+//		return this.getSession().getRequestService().
+//							createFullyQualifiedUrl( urlContext,
+//										     		 relativeUrl);
+//	}
+//	return this.getSession().getRequestService().createFullyQualifiedUrl(relativeUrl);
+//	
+//}
+//
+//AbstractTagImpl.prototype.createQualifiedUrlAsString = function( relativeUrl ) {
+//    var urlContext = this.getUrlContext();
+//    if ( urlContext != null ) {
+//        return this.getSession().getRequestService().
+//        	createFullyQualifiedUrlAsString( urlContext, relativeUrl );
+//    }
+//    return this.getSession().getRequestService().
+//    					createFullyQualifiedUrlAsString( relativeUrl );
+//}
+
+/**
+ * This method is used to fire an event in a standard manner.
+ * The ClientEvent encapsulates any extra info in the event. The eventValue
+ * should be something like "mco://myMco.do()" or "mypage.jsp".
+ * If the eventName is not registered on the element this method
+ * simply returns.
+ * 
+ * @param eventName The name of the event, like onCommand
+ * @param eventValue The value of the event, like "mco://myMco.do()"
+ * @param eventElement The element the event is registered on
+ * @param clientEvent The ClientEvent that contains any extra information - may be null.
+ * @return TODO
+ */
+AbstractTagImpl.prototype.fireEvent = function( eventName, eventValue, eventElement,
+												clientEvent ) {
+	var session = this.getSession();
+	
+	//if they didn't pass in an event element use our element
+	if ( eventElement == null ) {
+		eventElement = this.getElement();
+	}
+	
+	//if they didn't pass in an event value
+	//use the value in the dom, if they have
+	//onCommand="myPage" use "myPage" as the event value
+	if ( eventValue == null ) {
+		eventValue = eventElement.getAttribute( eventName );
+	}
+	
+	//if there was no event value we have noone listening
+	//for the event so just return
+	if ( eventValue == null ) {
+		return null;
+	}
+	
+	if ( clientEvent == null ) {
+		clientEvent = new ClientEvent( eventElement, this.getSession());
+	}
+	
+	clientEvent.id = eventElement.getAttribute( "id" );
+	clientEvent.event = eventName;
+	
+	//addInvokerInfo(clientEvent,eventElement);
+	return session.getEventHandler().fireEvent( eventName, eventValue,
+												eventElement,clientEvent );	
+}
+
+
+//	/**
+//	 * If an event like onCommand takes place, it may take place on a menuItem
+//	 * that was inside a popupMenu, and you would like to know what the
+//	 * menu was currently attached to. This does that by
+//	 * adding the "invoker" field with the proper ID.
+//	 * @param event
+//	 * @param sourceComponent
+//	 */
+//	private void addInvokerInfo(ClientEvent event, Element sourceElement){
+//		AbstractTagImpl tag = getUiContentHandler().getHandlerForElement(sourceElement);
+//		if (! (tag instanceof AwtComponentBridge)) return;
+//		Component parent = ((AwtComponentBridge)tag).getUiComponent();
+//		
+//		for(;;){
+//			if (parent==null) break;
+//			
+//			if (parent instanceof NPopup){
+//				
+//				//get the reference of the popup, if that doesn't work
+//				//get the actual Component invoker.
+//				Object reference = ((NPopup)parent).getReference();
+//				if (reference==null) reference = ((NPopup)parent).getInvoker();
+//				
+//				//if we found something, see if it has a handler,
+//				//and if so plug in that ID and name.
+//				if (reference!=null){
+//					Element referenceElement = null;
+//					
+//					//in the case of cell there is no mapping of peer
+//					//to to bridge, so the reference is just to the cell 
+//					//element itself
+//					if (reference instanceof Element){
+//						referenceElement = (Element) reference;
+//					}
+//					else{
+//						
+//						//problem: we get the handler for the peer, but this
+//						//could be either <valueComboBox> or the underlying
+//						//<comboBox>. Right now we return than handler for
+//						//comboBox itself. However, the NAME and ID
+//						//of the <comboBox> should be the same as for 
+//						//<valueComboBox>
+//						tag = getUiContentHandler().getHandlerForPeer(reference);
+//						if (tag!=null){
+//							referenceElement = tag.getElement();
+//						}
+//					}
+//					
+//					if (referenceElement!=null){
+//						event.setParameter("invoker",referenceElement.getAttribute("id"));
+//						String name = referenceElement.getAttribute("name");
+//						if (name==null) name = "";	
+//						event.setParameter("invokerName",name);
+//					}	
+//				}
+//			}
+//			if (parent instanceof NPanel){
+//				parent = ((NPanel)parent).getLogicalParent();
+//			}
+//			else{
+//				parent = parent.getParent();
+//			}
+//			
+//		}	
+//	}
+//		
+/**
+ * Returns the UiContentHandler. This handler can be used to 
+ * look up a tag by element, or an element by tag, as well as to parse
+ * child elements.
+ * 
+ * TODO this tag can exist in documents OTHER than the UI document,
+ * this is not a good way to do this, we should really have a generic
+ * getContentHandler() based on the document the element we manage
+ * belongs to.
+ * 
+ * @return The UiContentHandler.
+ */
+AbstractTagImpl.prototype.getUiContentHandler = function() {
+	return this.getSession().getUiDocumentHandler();
+}
+//	
+//
+//	public void writeBackTextNode(int index, String value){
+//		synchronized(getUiDocument().getDomSynchronizationObject()){
+//			getElement().removeStructureChangeListener(this);
+//			getElement().removeChildAt(index);
+//			getElement().insertChildAt(index,value);
+//			getElement().addStructureChangeListener(this);
+//		}
+//	}
+//	
+//
+//	
+	/**
+	 * This method can be used to write values back into the document.
+	 * For example, if a user enters text into a textField and we want the 
+	 * "text" attribute to reflect the text, we can call 
+	 * writeBackAttribute("text",getText()).
+	 * <br><br>
+	 * This will not signal the tag-handler that an attribute has changed. The assumption
+	 * is that the tag-handler is what initiated the write back. Other AttributeChangeListeners
+	 * will be called.
+	 * 
+	 * @param name The name of the attribute to write.
+	 * @param value The new value.
+	 */
+	 
+AbstractTagImpl.prototype.writeBackAttribute = function(name, value) {
+	this.getElement().removeAttributeChangeListener(this);
+	this.getElement().setAttribute(name,value);
+	this.getElement().addAttributeChangeListener(this);
+}
+//	
+//	private void writeBackAttribute(Element e, String name, String value){
+//		synchronized(getUiDocument().getDomSynchronizationObject()){
+//			e.removeAttributeChangeListener(this);
+//			e.setAttribute(name,value);
+//			e.addAttributeChangeListener(this);
+//		}
+//	}
+//
+//	
+//	/**
+//	 * This method can be used to remove values the document.
+//	 * For example, if a user deletes all text from a textField and we want the 
+//	 * "text" attribute to reflect the lack of text, we can call 
+//	 * writeBackRemoveAttribute("text").
+//	 * <br><br>
+//	 * This will not signal the tag-handler that an attribute has been removed. The assumption
+//	 * is that the tag-handler is what initiated the write back. Other AttributeChangeListeners
+//	 * will be called.
+//	 * 
+//	 * @param name The name of the attribute to remove.
+//	 */
+//	public void writeBackRemoveAttribute(String name){
+//		synchronized(getUiDocument().getDomSynchronizationObject()){
+//			getElement().removeAttributeChangeListener(this);
+//			getElement().removeAttribute(name);
+//			getElement().addAttributeChangeListener(this);
+//		}
+//	}
+//	
+//	
+//	
+//	
+
+/**
+ * This method is called by onAttributeSet(), which catches any AttributeConversioExceptions
+ * that may have been produced and calls reportInvalidXmlException on them.
+ * Subclasses should typically override this method rather than onAttributeSet.
+ * 
+ * @param event AttributeChangeEvent
+ * @throws AttributeConversionException
+ */
+AbstractTagImpl.prototype.attributeSet = function( event ) {	
+	// NO-OP
+}
+
+/**
+ * This method is included to conform to the StructureChangeListener interface.
+ * @param e The StructureChangeEvent
+ */
+AbstractTagImpl.prototype.beforeChildAdded = function( e ) {
+//		
+//		if (e.getType() == StructureChangeEvent.TEXT_NODE) {
+//			ResolutionHandler resolverRegistry = getUiContentHandler().getResolverRegistry();
+//			try{
+//				String value = (String) e.getChange();
+//				
+//				if (resolverRegistry.needsResolving(value)){
+//					String newValue = resolverRegistry.
+//						resolveTextNode(getElement(),value,e.getIndex());
+//					e.setChange(newValue);
+//				}
+//				else{
+//				
+//					//if the set us to ignore escaping the call to
+//					//unescape string just returns the original value
+//					e.setChange(resolverRegistry.unescapeString(value));
+//				}
+//			}
+//			catch(ResolverException ex){
+//				getSession().handleException(ExceptionContext.RESOLVER_ERROR,ex);
+//			}
+//			catch(EscapeSyntaxException ex){
+//				getSession().handleException(ExceptionContext.RESOLVER_ERROR,ex);
+//			}
+//		}
+}
+	
+/**
+ * This method is included to conform to the StructureChangeListener interface.
+ * @param e The StructureChangeEvent
+ */
+AbstractTagImpl.prototype.beforeChildRemoved = function( e ) {}
+
+/**
+ * Subclasses should override this method to handle dynamic addition of children.
+ * @param e The StructureChangeEvent
+ */
+AbstractTagImpl.prototype.onChildAdded = function( e ) {}
+
+/**
+ * Subclasses should override this method to handle dynamic removal of children.
+ * Subclasses must either call super.onChildRemoved() or invoke
+ * afterChildRemoved() directly.
+ * @param e The StructureChangeEvent
+ */
+AbstractTagImpl.prototype.onChildRemoved = function( e ) {
+	if ( e.getType() == StructureChangeEvent.ELEMENT_NODE ) {
+		this.getUiContentHandler().deregister( e.getChange() );	
+	}
+}
+
+/**
+ * This must be called when a child element is removed
+ * from it's parent. This will call getUiContentHandler().deregister()
+ * which will in turn de-register the child handler as an MCO and
+ * perform recursive cleanup.
+ * 
+ * @param e The StructureChangeEvent with the element being removed.
+ */
+AbstractTagImpl.prototype.afterChildRemoved = function( e ) {
+	if ( e.getType() == StructureChangeEvent.ELEMENT_NODE ) {
+		this.getUiContentHandler().deregister( e.getChange() );	
+	}
+}
+
+/**
+ * This method calls attributeSet(), catches any AttributeConversioExceptions
+ * that may have been produced and calls reportInvalidXmlException on them.
+ * Subclasses should typically override attributeSet rather than this method.
+ * 
+ * @param e The AttributeChangeEvent
+ */
+AbstractTagImpl.prototype.onAttributeSet = function( e ) {
+	try {
+		this.attributeSet( e );
+	} catch( ex ) {
+		this.reportInvalidXmlException( e.getName(), e.getNewValue(), 
+										this.getElement(), ex );
+	}
+}
+
+/**
+ * Subclasses should override this method to handle dynamic removal of attributes.
+ * Removal of attributes should typically revert to a default behavior and act as though
+ * the attribute had never been set.
+ * 
+ * @param e The AttributeChangeEvent
+ */
+AbstractTagImpl.prototype.onAttributeRemoved = function( e ) {}
+
+/**
+ * @param e The AttributeChangeEvent
+ */
+AbstractTagImpl.prototype.beforeAttributeRemoved = function( e ) {}
+
+/**
+ * @param e The AttributeChangeEvent
+ */	
+AbstractTagImpl.prototype.beforeAttributeSet = function( e ) {
+//		ResolutionHandler resolverRegistry = getUiContentHandler().getResolverRegistry();
+//		String attributeName = e.getName();
+//		String attributeValue = e.getNewValue();
+//
+//		try{
+//		    if (resolverRegistry.needsResolving(attributeValue)){
+//		        String newValue = resolverRegistry.resolveAttribute(getElement(),attributeName,attributeValue);
+//				e.setNewValue(newValue);
+//		    }
+//		    else{
+//				e.setNewValue(resolverRegistry.unescapeString(attributeValue));
+//			}   
+//		    
+//		    //now that we handled escaping also handle the fact that the thing
+//		    //can be a url that needs to be qualified
+//		    attributeValue = e.getNewValue();
+//            
+//	        String newAttributeValue = qualifyToFullUrl(attributeName, attributeValue,this);
+//			if ( newAttributeValue != null && !newAttributeValue.equals(attributeValue)){
+//				e.setNewValue(newAttributeValue);
+//			}
+//		}
+//		catch(ResolverException ex){
+//			getSession().handleException(ExceptionContext.RESOLVER_ERROR,ex);
+//		}
+//		catch(EscapeSyntaxException ex){
+//			getSession().handleException(ExceptionContext.RESOLVER_ERROR,ex);
+//		}
+}
+
+//	/**
+//	 * Generate a new full url string value if the attribute value
+//	 * can be properly qualified into an http, https, or classpath
+//	 * URL, otherwise returns null.
+//	 * 
+//	 * @param attributeName The name of the attribute to qualify
+//	 * @param attributeValue The value of the attribute to qualify
+//	 * @return A qualified URL or null if it was not qualifiable
+//	 */
+//	public static String qualifyToFullUrl( String attributeName, String attributeValue,
+//		AbstractTagImpl tagHandler ) {
+//	    
+//	    //if it's an object event we shouldn't qualify it!
+//	    if ( ((ClientSessionImpl)tagHandler.getSession()).getEventHandler().
+//	            qualifyObjectUrl(attributeValue)!=null){
+//	        return null;
+//	    }
+//     	
+//	    if (attributeValue.startsWith(EventHandler.CLASSPATH_PREFIX)){
+//     		return null;
+//     	}
+//
+//     	// little optimization
+//     	if ( attributeName.equals(XmlTokens.ID) || attributeName.equals(XmlTokens.TEXT) ) return null;
+//     	
+//     	if ( UrlPathUtil.isFullyFormattedUrl(attributeValue)) return null;
+//     	
+//     	for ( int i = 0; i<XmlTokens.ON_EVENT_NAMES.length; i++){
+//     		if ( XmlTokens.ON_EVENT_NAMES[i].equals(attributeName) ){
+//     			try {
+//					return tagHandler.createQualifiedUrlAsString(attributeValue);
+//				} catch (MalformedURLException e) {
+//					e.printStackTrace();
+//				}
+//     		}
+//     	}
+//     	
+//     	for ( int i = 0; i<IMG_TAG_NAMES.length; i++){
+//     		if ( IMG_TAG_NAMES[i].equals(attributeName)){
+//     			try {
+//					return tagHandler.createQualifiedUrlAsString(attributeValue);
+//				} catch (MalformedURLException e) {
+//					e.printStackTrace();
+//				}
+//     		}
+//     	}
+//		
+//		return null;
+//	}
+//	
+
+//	
+//
+//	private void writeBackRemoveChild(int index){
+//		synchronized(getUiDocument().getDomSynchronizationObject()){
+//			getElement().removeStructureChangeListener(this);
+//			getElement().removeChildAt(index);
+//			getElement().addStructureChangeListener(this);
+//		}
+//	}
+//}
+
+/**
+ * This method is used to report problems in attribute parsing
+ * in a standardized manner. Subclasses should call this if they 
+ * encounter an attribute that is not formatted correctly.
+ * 
+ * @param attributeName The name of the attribute.
+ * @param attributeValue The (bad) value of the attribute.
+ * @param el The element the error occured on.
+ * @param ex The exception encapsulating the error, usually an 
+ * AttributeConversionException.
+ */
+AbstractTagImpl.prototype.reportInvalidXmlException = function( attributeName,
+							attributeValue, el, ex ) {
+	var exception = this.constructInvalidXmlException( 
+	                                attributeName, attributeValue, el, ex );
+	// exception.enableShortStackTrace();
+    this.getSession().handleException(  exception );
+}
+
+/**
+ * Constructs an InvalidXmlException reporting
+ * a bad attribute value; the exception is created and returned
+ * without being reported.
+ * 
+ * @param attributeName The name of the attribute.
+ * @param attributeValue The (bad) value of the attribute.
+ * @param e The element the error occured on.
+ * @param ex The exception encapsulating the error, usually an 
+ * AttributeConversionException.
+ * @return InvalidXmlException object
+ */
+AbstractTagImpl.prototype.constructInvalidXmlException = function( attributeName,
+														attributeValue, e, ex ) {
+    var exception = new InvalidXmlException(
+            InvalidXmlException.BAD_ATTRIBUTE_WITH_ROOT_CAUSE,
+            new Array( attributeName, attributeValue, ex.getMessage(),
+            InvalidXmlException.toString( e ),
+            InvalidXmlException.toString( e.getParent() )),
+            ex );
+    return exception;
+}
+
+AbstractTagImpl.prototype.getSession = function() {
+	return this._clientSession;
+}
+
+/**
+ * Called during initialization process.
+ */
+AbstractTagImpl.prototype.setSession = function( session ) {
+	this._clientSession = session;
+}

Propchange: incubator/xap/trunk/src/xap/taghandling/AbstractTagImpl.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js (added)
+++ incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,272 @@
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+/**
+ * @fileoverview PluginDocumentHandler manages creating bridge classes
+ * for tags on a single document.
+ * 
+ * @author ikaplansky
+ * @author jmargaris
+ */
+ 
+/**
+ * Creates a new PluginDocumentHandler for the given document and document name.
+ * 
+ * @class PluginDocumentHandler manages creating bridge classes
+ * for tags on a single document. PluginDocumentHandler listens for structure
+ * change events on the document it manages. When items are added anywhere
+ * in the document this handler is signalled and goes through the logic
+ * of looking up the bridge class based on the tag and namespace
+ * for the given document, instantiating the bridge class and setting it up.
+ *
+ * 
+ * @param {ClientSession} clientSession The session object
+ * @param {Document} doc The document to handle
+ * @param {String} documentName The logical name of the document to handle,
+ *  the name the document is registered under.
+ */
+
+function PluginDocumentHandler( clientSession, doc, documentName ) {
+	// A map of XML elements to their bridge classes.
+	this._elementsToBridges = new Hashtable();
+	// Map from peer objects back to their bridge classes that drive them
+	this._peersToBridges = new Hashtable();
+	this._clientSession = clientSession;
+	this._documentName = documentName;
+	doc._addSystemStructureChangeListener( this );
+}
+
+/** @private */
+PluginDocumentHandler.s_log = LogFactory.getLog( "PluginDocumentHandler" );
+
+
+//-----------------------------------------------------------------------
+// StructureChangeListener Implementation.
+//-----------------------------------------------------------------------
+
+/**
+ * Implements the StructureChangeListener interface - 
+ * when a child is added parseChild() is called on the added Element
+ * which begins the recursive task of creating all the bridge
+ * classes for the element tree that was added to the document.
+ * 
+ * @param e StructureChangeEvent
+ */
+PluginDocumentHandler.prototype.onChildAdded = function ( e ) {
+    // Technically they can replace the root node:
+    //   e.getType() == StructureChangeEvent.ROOT_NODE
+    // TODO - this might be good to account for in the
+    //        future , for now we don't really care
+ 	if( e.getType() == StructureChangeEvent.TEXT_NODE ) {
+ 		return;
+ 	}
+	this.parseChild( e.getChange() );
+}
+
+/**
+ * No-op StructureChangeListener implementation.
+ * We might want to tie this in to the dergister logic?
+ */
+PluginDocumentHandler.prototype.onChildRemoved = function( e ) {}
+
+/**
+ * No-op StructureChangeListener implementation.
+ */
+PluginDocumentHandler.prototype.beforeChildAdded = function( event ) {}
+ 
+/**
+ * No-op StructureChangeListener implementation.
+ */
+PluginDocumentHandler.prototype.beforeChildRemoved = function( event ) {}
+ 
+ 
+/**
+ * Called from AbstractTagImpl afterChildRemoved() to recursively
+ * clean up the removed element tree. This will de-register
+ * all the handlers as MCOs and removes them from the
+ * 2 way element<->handler mapping.
+ * 
+ * @param e The element being removed from the document.
+ */
+PluginDocumentHandler.prototype.deregister = function( el ) {
+	var handler = this.getHandlerForElement( el ); 
+	if ( handler != null ) {
+		this._elementsToBridges.remove( el );
+		
+		//TODO all handlers should have some unload or some
+		//other lifecycle notification
+		if (handler.unload){
+			handler.unload();
+		}
+		el.removeAttributeChangeListener( handler );
+		el.removeStructureChangeListener( handler );
+	}
+	
+	//recursively de-register all children
+	for ( var i = 0; i < el.childNodes.length; i++ ) {
+		var child = el.childNodes[i];
+		if ( child.nodeType == DOM_ELEMENT_NODE ) {
+			this.deregister( child );
+		}
+	}
+}
+
+/**
+ * Parses an XML Element and returns a new instance of the tag-handling
+ * bridge class that the tag name was mapped to. This is called whenever a 
+ * new document fragment is added to the UI document, and from
+ * parseInitialChildren() in AbstractTagImpl.
+ * 
+ * @param childElement The element to parse and create the tag<->tag-handler 
+ * mapping for.
+ * @return A new instance of the tag-handling class or null if no mapping exists.
+ */
+PluginDocumentHandler.prototype.parseChild = function( childElement ) {
+	var handler = null;
+	
+	var pluginRegistry = this._clientSession.getPluginRegistry();
+	try {
+		//step 1: Look up the class name for this tag name,
+		//then instantiate that class instance
+		var tagName = childElement.getLocalName();
+		var namespace = childElement.getNamespaceUri();
+		var bridgeClass = pluginRegistry.getTagMapping( tagName, namespace,
+															 this._documentName );
+	
+		//if the implementing class name is null do what we used to do
+		//and print out an error
+		if ( bridgeClass == null ) {
+			PluginDocumentHandler.s_log.debug( "No mapping for tag name [" + 
+					tagName + "] with namespace [" +
+					namespace + "] on document [" + this._documentName + "]");
+			PluginDocumentHandler.s_log.error( "No mapping found for tag " + 
+										tagName + ", namespace=" + namespace );
+			return null;
+		}
+		//if it's not a string this means it is a valid tag but
+		//not mapped to a class, so just return
+		//TODO this logic needs cleanup here, the idea is to let them register
+		//tags that don't map to anything but also aren't considered errors
+		else if (( typeof bridgeClass ) != "string" ) {
+			return null;
+		}
+		var handler = null;
+		
+		//now that we have the name of the bridge class, make a
+		//new one
+		try {
+			handler = eval( "new " + bridgeClass + "()" );
+		} 
+		catch( ex ) {
+			PluginDocumentHandler.s_log.exception( "Exception during eval:" + 
+												   ex.toString() );
+		}	
+		
+
+		//step 2: hook up the element and the bridge class in the various
+		//hashes. Do this early to avoid problems later.
+		this.setHandlerForElement( childElement, handler );
+
+		//when we call their code they can change some stuff
+		//step 3: inject the session into the tag handler
+		handler.setSession( this._clientSession );
+
+		//step 4: if it is a structure change listener and/or attribute change listener,
+		//automatically hook it up as a listener for the source element
+		
+		
+		//we had an opimization here before for cells that didn't add
+		//the structure change listener since cells can't have children,
+		//we should consider generalizing that and putting it back in
+		childElement.addStructureChangeListener( handler );
+		childElement.addAttributeChangeListener( handler );	
+			
+			
+		//step 5: call setElement(), this is the signal that the bridge
+		handler.setElement( childElement );
+		handler.init();
+     
+		//finally fire the "onCreate" event
+		handler.fireEvent( "onCreate" ); 
+	} 
+	catch( ex ) {
+		this._clientSession.handleException( new XapException("blah",null, ex,"PluginDocumentHandler.parseChild"  ));
+	}		
+	return handler;
+}
+
+
+
+/**
+ * Returns the tag-handling class mapped to the given Element.
+ * @param e The Element to look up the tag-handler for.
+ * @return The tag-handling class.
+ */
+PluginDocumentHandler.prototype.getHandlerForElement = function( el ){
+ 	return this._elementsToBridges.get( el );
+}
+ 
+/**
+ * For internal use only.
+ */
+PluginDocumentHandler.prototype.setHandlerForElement = function( el, tagImpl ){
+	this._elementsToBridges.put( el, tagImpl );
+}
+ 
+/**
+ * Sets up a mapping between a bridge tag-handler
+ * and the component it controls. This can be used to look up
+ * the bridge from the peer. For example, given a JButton
+ * to look up the subclass of SwingBridge that controls that JButton
+ * instance.<br><br>
+ * This is called automatically by ContainerBridge
+ * in setUiComponent().
+ * 
+ * @param peer The controlled object.
+ * @param bridge The bridge class that controls that object.
+ */
+PluginDocumentHandler.prototype.setHandlerForPeer = function( peer, tagImpl ) {
+	this._peersToBridges.put( peer, tagImpl );
+}
+ 
+/**
+ * Removes the mpping between the peer and the handler. 
+ * This should be called in in the AbstractTagImpl
+ * deregister() to clean up any references.
+ * @param peer The peer object to remove the mapping for.
+ */
+PluginDocumentHandler.prototype.removeHandlerForPeer = function( peer ) {
+	this._peersToBridges.remove( peer );
+}
+ 
+/**
+ * Returns the bridge class that controls the given component.
+ * This can be used to look up
+ * the bridge from the peer. For example, given a JButton
+ * to look up the subclass of SwingBridge that controls that JButton
+ * instance.<br><br>
+ * 
+ * Note that when using Composite Components it is possible for
+ * two handlers to map to the same peer object. For example if the developer
+ * creates a "myTable" component that wraps the standard "table",
+ * both the handler for "myTable" and the handler for "table"
+ * itself control the same table peer object.
+ * @param peer The controlled object to look up the bridge for.
+ */
+PluginDocumentHandler.prototype.getHandlerForPeer = function( peer ) {
+	return this._peersToBridges.get( peer );
+}
\ No newline at end of file

Propchange: incubator/xap/trunk/src/xap/taghandling/PluginDocumentHandler.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js (added)
+++ incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,77 @@
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+/**
+ * @fileoverview PluginRegistry keeps track of all the tags
+ * for various documents and namespaces and what they map to. 
+ * 
+ * @author ikaplansky
+ * @author jmargaris
+ */
+ 
+/**
+ * Creates a new PluginRegistry.
+ * 
+ * @class PluginRegistry keeps track of all the tags
+ * for various documents and namespaces and what they map to. Currently
+ * this class maps tags to bridge class names without any regard for
+ * namespace or document name. In the future it needs to allow the same
+ * tag name to have different meaning depending on namespace and the document
+ * the tag appears in. TODO
+ *
+ */
+function PluginRegistry() {
+	
+	this._tagToBridgeClassName = new Hashtable();
+	
+	//zimbra components
+	this._tagToBridgeClassName.put( "panel", "DwtCompositeBridge" );
+	this._tagToBridgeClassName.put( "label", "DwtLabelBridge" );
+	this._tagToBridgeClassName.put( "button", "DwtButtonBridge" );
+	this._tagToBridgeClassName.put( "tabPane", "DwtTabViewBridge" );
+	this._tagToBridgeClassName.put( "tab", "DwtTabBridge" );
+	this._tagToBridgeClassName.put( "splitPane", "DwtSplitterBridge" );
+	this._tagToBridgeClassName.put( "left", "DwtSplitChildBridge" );
+	this._tagToBridgeClassName.put( "right", "DwtSplitChildBridge" );
+	this._tagToBridgeClassName.put( "top", "DwtSplitChildBridge" );
+	this._tagToBridgeClassName.put( "bottom", "DwtSplitChildBridge" );
+	this._tagToBridgeClassName.put( "tree", "DwtTreeBridge" );
+	this._tagToBridgeClassName.put( "treeItem", "DwtTreeItemBridge" );
+	this._tagToBridgeClassName.put( "textField", "DwtTextFieldBridge" );
+	this._tagToBridgeClassName.put( "verticalLayoutPanel", "DwtVerticalLayoutPanelBridge" );
+	this._tagToBridgeClassName.put( "horizontalLayoutPanel", "DwtHorizontalLayoutPanelBridge" );
+	
+	//basic components
+	this._tagToBridgeClassName.put( "textView", "TextViewBridge" );
+	
+	//add custom tags here
+	this._tagToBridgeClassName.put( "gMap", "GoogleMapBridge" );
+	this._tagToBridgeClassName.put( "infoWindow", "GoogleInfoWindowBridge" );
+	this._tagToBridgeClassName.put( "marker", "GoogleMarkerBridge" );
+	this._tagToBridgeClassName.put( "markers", "GoogleMarkersBridge" );
+	this._tagToBridgeClassName.put( "icons", "GoogleIconsBridge" );
+	this._tagToBridgeClassName.put( "icon", "GoogleIconBridge" );
+}
+
+/**
+ * Given the tag name, namespace uri and the document name that tag appears in,
+ * return the bridge class name that the tag/namespace/document maps to,
+ * if any.
+ */
+PluginRegistry.prototype.getTagMapping = function( tagName, nameSpace, documentName ) {
+	return this._tagToBridgeClassName.get( tagName );	
+}

Propchange: incubator/xap/trunk/src/xap/taghandling/PluginRegistry.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js (added)
+++ incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,240 @@
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+/**
+ * @fileoverview Work in progress.
+ *
+ * @author jmargaris
+ * 
+ */
+ 
+ 
+/**
+ * A constructor.
+ * 
+ * @class This is going to replace the functionality in PluginRegistry (perhaps
+ * with a rename). This class is responsible for parsing a plugin mapping file
+ * and setting up the proper mappings. A plugin mapping file defines
+ * tags that map to classes. Each entry applies to a single namespace
+ * and to a single document. For example, the <button> tag would apply
+ * to the UI namespace and the UI document. Using button without the UI namespace
+ * or outside of the UI document would have no effect.
+ * 
+ * It is also possible to have a tag map to no class. That way we will not
+ * report the tag as unrecognized.
+ */
+
+
+
+function PluginRegistryImpl( session ){
+	this._pluginLifecycleObjects = new Array();
+	this._tagDefinitions = new Hashtable();
+	this._tagMappings = new Hashtable();
+	this._session = session;
+}
+
+PluginRegistryImpl.s_log = LogFactory.getLog( "PluginRegistryImpl" );
+
+PluginRegistryImpl.TAG_MAPPINGS_PATH = "/plugin/tag-mappings";
+
+PluginRegistryImpl.UNMAPPED_TAGS_PATH = "/plugin/unmapped-tags"
+
+PluginRegistryImpl.PLUGIN_LIFECYCLE_CLASS_PATH = "/plugin/@class";
+
+PluginRegistryImpl.NO_MAPPED_CLASS =  new Object();
+	
+	
+//TODO would this whole thing make more sense as a generic namespace
+//handler?? Or instead of parsing XML just have js code do this directly?
+//is the overhead of XML configuration worth it? simpler?
+
+/**
+ * Adds a plug-in decription file.
+ * 
+ * @param fileContents a String representing the actual content (NOT path)
+ * of the description file
+ */
+PluginRegistryImpl.prototype.addPluginDescription = function( fileContents ){
+	
+	PluginRegistryImpl.s_log.debug("Add plugin description");
+	var parser = new SaxParser( new SaxContentHandler() );
+	var pluginDocument =  null;
+	
+	try{
+		pluginDocument = parser.parse( fileContents );
+	}
+	catch( exception ){
+		this._session.handleException( exception );
+		return;
+	}
+	
+
+	//TODO this returs what an array of nodes?
+	var tagMappingSections = 
+		xpathDomEval(PluginRegistryImpl.TAG_MAPPINGS_PATH , pluginDocument);	
+	PluginRegistryImpl.s_log.debug(tagMappingSections.value.length + " mapped tags");
+	this._parseTagMappingElements(tagMappingSections.value,true);		
+
+	PluginRegistryImpl.s_log.debug("Parse unmapped tags");
+	tagMappingSections = 
+		xpathDomEval(PluginRegistryImpl.UNMAPPED_TAGS_PATH , pluginDocument);	
+	PluginRegistryImpl.s_log.debug(tagMappingSections.value.length + " unmapped tags");
+	this._parseTagMappingElements(tagMappingSections.value,false);
+
+	//TODO this returns an array but we want a string, get the first element node value?
+	var lifecycleClassName = 
+		xpathDomEval(PluginRegistryImpl.PLUGIN_LIFECYCLE_CLASS_PATH , pluginDocument).value[0];	
+		
+	PluginRegistryImpl.s_log.debug("lifecycle class = " + lifecycleClassName);
+
+	if (lifecycleClassName && lifecycleClassName.length >0){
+		try{
+			//TODO we need a generic "load this bean" type of method
+			var lifecycleObject = eval("new " + lifecycleClassName + "()");
+			
+			//TODO maybe we should just have a container for lifecycle objects
+			//so that you can look them up and the notification is done via
+			//standard container mechanism? Allow them to assign IDs etc?
+			if (lifecycleObject.pluginLoaded){
+				lifcycleObject.pluginLoaded(this._session);
+			}
+			
+			//TODO call unloaded when unloaded?
+			this._pluginLifecycleObjects.push(lifecycleObject);
+		}
+		catch( exception ){
+			this._session.handleException( exception );
+		}
+	}
+}
+	
+/**
+ * Returns the original definition element that came from the tag-mapping/
+ * plugin file representing this tag/namespace combo
+ */	
+PluginRegistryImpl.prototype.getPluginDefinition = function( tagName, nameSpace, documentName){
+	this._tagDefinitions.get(PluginRegistryImpl._createHashtableKey(tagName,nameSpace,documentName));	
+}	
+
+	
+/**
+ * This will return one of three things:
+ * 1: A string representing the class name
+ * 2: null, indicating unmapped
+ * 3: A non-string object, indicating unmapped purposely
+ */
+PluginRegistryImpl.prototype.getTagMapping = function(tagName, nameSpace, documentName){
+	return this._tagMappings.get(PluginRegistryImpl._createHashtableKey(tagName,nameSpace,documentName));
+}
+	
+	
+	
+/**
+ * Does the work of parsing the main tag-mapping blocks
+ * @param tagMappingSections The array of elements representing
+ * tag-mapping and unmapped-tags roots
+ * @param isMappedTag if true, each item should map to a class
+ */
+PluginRegistryImpl.prototype._parseTagMappingElements = function(tagMappingSections, isMappedTag){
+		
+	//for each tag in the block
+	for (var section =0; section<tagMappingSections.length; section++){
+		var tagMappingRoot = tagMappingSections[section];
+		
+		var documentName = tagMappingRoot.getAttribute("document");
+		if (documentName==null){
+			documentName = DocumentContainer.UI_DOCUMENT_NAME;
+		}
+		var nameSpace = tagMappingRoot.getAttribute("namespace");
+		
+		//for each child of that tag in the block
+		for (var i = 0; i<tagMappingRoot.childNodes.length; i++){
+			var tagElement = tagMappingRoot.childNodes[i];
+			
+			var className = null;
+			var tagName = null;
+			
+			//v2 syntax:
+			//<mapping name="pieChart" class="piechart.PieChartBridge"/>
+			if (tagElement.getLocalName()=="mapping"){
+				tagName = tagElement.getAttribute("name");
+				
+				if (tagName==null || tagName.length==0){
+					//TODO report exception
+					continue;
+				}
+				
+				if (isMappedTag){
+					className = tagElement.getAttribute("class");
+					if (className==null || className.length==0){
+						//TODO report exception
+						continue;
+					}
+				}
+				//if we aren't supposed to be mapped to anything
+				//don't look for class
+				else{
+					className = PluginRegistryImpl.NO_MAPPED_CLASS
+				}
+			}
+			else{
+				//TODO report exception	
+				
+			}
+			
+			PluginRegistryImpl.s_log.debug("Add tag mapping:" + tagName + ":" + className);
+			this._addTagMapping(tagName,className,nameSpace,documentName,tagElement);
+		}
+	}
+}
+
+
+PluginRegistryImpl.prototype.toString = function(){
+	return this._tagMappings.toString();
+}
+/**
+ * @param {String} tagName The name of the tag
+ * @param {Object} className The name of the class or the special NO_MAPPED_CLASS object
+ * @param {String} nameSpace The namespace URI.
+ * @param {String} documentName The name of the document the tag applies to
+ * @param {XapElement} originalDefinition The tag definition element
+ */
+PluginRegistryImpl.prototype._addTagMapping = function( tagName, className, nameSpace,
+	documentName, originalDefinition){
+
+	//error: duplicate tag name
+	if (this.getTagMapping(tagName,nameSpace,documentName)!=null){
+		//TODO report exception but overwrite
+	}
+	
+	var hashKey = PluginRegistryImpl._createHashtableKey(tagName,nameSpace,documentName);
+	this._tagMappings.put(hashKey,className);
+	this._tagDefinitions.put(hashKey,originalDefinition);
+}
+
+
+
+
+
+PluginRegistryImpl._createHashtableKey = function(tagName, nameSpace, documentName){
+//TODO we should consider no namespace the same as default?
+//if so make that work for stylsheets, xupdate, etc
+//if (nameSpace == null) {
+//		nameSpace = "http://xal.org/xal";
+//	}
+	return tagName + ":" + nameSpace + ":"  + documentName;
+}

Propchange: incubator/xap/trunk/src/xap/taghandling/PluginRegistryImpl.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/src/xap/taghandling/plugin.xml
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/src/xap/taghandling/plugin.xml?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/src/xap/taghandling/plugin.xml (added)
+++ incubator/xap/trunk/src/xap/taghandling/plugin.xml Thu Jun 22 15:59:35 2006
@@ -0,0 +1,31 @@
+<plugin>
+	<!-- mappings that apply to the document named "dataSources" -->
+	<tag-mappings namespace="http://www.openxal.org/xal" document="xal">
+		<mapping class="DwtCompositeBridge" name="panel"/>
+		<mapping class="DwtLabelBridge" name="label"/>
+		<mapping class="DwtButtonBridge" name="button"/>
+		<mapping class="DwtTabViewBridge" name="tabPane"/>
+		<mapping class="DwtTabBridge" name="tab"/>
+		<mapping class="DwtSplitterBridge" name="splitPane"/>
+		<mapping class="DwtSplitChildBridge" name="left"/>
+		<mapping class="DwtSplitChildBridge" name="right"/>
+		<mapping class="DwtSplitChildBridge" name="top"/>
+		<mapping class="DwtSplitChildBridge" name="bottom"/>
+		<mapping class="DwtTreeBridge" name="tree"/>
+		<mapping class="DwtTreeItemBridge" name="treeItem"/>
+		<mapping class="DwtTextFieldBridge" name="textField"/>
+		<mapping class="DwtVerticalLayoutPanelBridge" name="verticalLayoutPanel"/>
+		<mapping class="DwtHorizontalLayoutPanelBridge" name="horizontalLayoutPanel"/>
+		
+		<mapping class="TextViewBridge" name="textView"/>
+	</tag-mappings>
+	
+	<tag-mappings namespace="http://www.google.com" document="xal">	
+		<mapping class="GoogleMapBridge" name="gMap"/>
+		<mapping class="GoogleInfoWindowBridge" name="infoWindow"/>
+		<mapping class="GoogleMarkerBridge" name="marker"/>
+		<mapping class="GoogleMarkersBridge" name="markers"/>
+		<mapping class="GoogleIconsBridge" name="icons"/>
+		<mapping class="GoogleIconBridge" name="icon"/>
+	</tag-mappings>
+</plugin>

Propchange: incubator/xap/trunk/src/xap/taghandling/plugin.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/xap/trunk/testsrc/XapUnitTestSuite.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/XapUnitTestSuite.html?rev=416494&r1=416493&r2=416494&view=diff
==============================================================================
--- incubator/xap/trunk/testsrc/XapUnitTestSuite.html (original)
+++ incubator/xap/trunk/testsrc/XapUnitTestSuite.html Thu Jun 22 15:59:35 2006
@@ -44,12 +44,12 @@
             return result;
         }
 
-        function tagsSuite( webappContext ) {
+        function taghandlingSuite( webappContext ) {
         	var result = new top.jsUnitTestSuite();
-        	result.addTestPage( webappContext + "/testsrc/xap/tags/_TestPluginRegistryImpl.html" );
-            result.addTestPage( webappContext + "/testsrc/xap/tags/_TestAbstractTagImpl.html" );
-            result.addTestPage( webappContext + "/testsrc/xap/tags/_TestPluginDocumentHandler.html" );
-            // result.addTestPage( webappContext + "/testsrc/xap/tags/_TestUiDocumentHandler.html" );
+        	result.addTestPage( webappContext + "/testsrc/xap/taghandling/_TestPluginRegistryImpl.html" );
+            result.addTestPage( webappContext + "/testsrc/xap/taghandling/_TestAbstractTagImpl.html" );
+            result.addTestPage( webappContext + "/testsrc/xap/taghandling/_TestPluginDocumentHandler.html" );
+            // result.addTestPage( webappContext + "/testsrc/xap/taghandling/_TestUiDocumentHandler.html" );
             return result;
         }
         
@@ -65,7 +65,7 @@
             var	webappContext = "/jsunit";
 
 			//suite.addTestSuite( testSuite( webappContext ));
-            suite.addTestSuite( tagsSuite( webappContext ) );
+            suite.addTestSuite( taghandlingSuite( webappContext ) );
            suite.addTestSuite( utilSuite( webappContext ) );
            suite.addTestSuite( xmlSuite( webappContext ) );
             suite.addTestSuite( mcoSuite( webappContext ) );

Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html Thu Jun 22 15:59:35 2006
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
+	"http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <title>ClientSession Unit Tests</title>
+    <link rel="stylesheet" type="text/css" href="/jsunit/jsunit/css/jsUnitStyle.css">
+    <script language="JavaScript" type="text/javascript" src="/jsunit/jsunit/app/jsUnitCore.js"></script>
+	<script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/util/Utils.js"></script>
+    <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/Xap.js"></script>
+    <script language="JavaScript" type="text/javascript">
+    	Xap.bootstrap( "/jsunit" );
+  	</script>
+</head>
+
+<body>
+    <script language="JavaScript" type="text/javascript">
+		function testAbstractTagImplMethods() {
+			var bridge = new AbstractTagImpl();
+			assertTrue( bridge != null );
+			assertTrue( bridge.setSession != null );
+		}
+    </script>
+</body>
+</html>
\ No newline at end of file

Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestAbstractTagImpl.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html Thu Jun 22 15:59:35 2006
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
+	"http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <title>ClientSession Unit Tests</title>
+    <link rel="stylesheet" type="text/css" href="/jsunit/jsunit/css/jsUnitStyle.css">
+    <script language="JavaScript" type="text/javascript" src="/jsunit/jsunit/app/jsUnitCore.js"></script>
+	<script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/util/Utils.js"></script>
+    <script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/Xap.js"></script>
+    <script language="JavaScript" type="text/javascript">
+    	Xap.bootstrap( "/jsunit" );
+    </script>
+
+</head>
+
+<body>
+    <script language="JavaScript" type="text/javascript">
+		function testPluginDocumentHandlerMethods() {
+			DBG = new AjxDebug( AjxDebug.NONE, null, false );
+			var session = new ClientSession( "/xap" );
+		}
+    </script>
+</body>
+</html>
\ No newline at end of file

Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginDocumentHandler.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html Thu Jun 22 15:59:35 2006
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
+	"http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<title>Element Unit Tests</title>
+	<link rel="stylesheet" type="text/css" href="/jsunit/jsunit/css/jsUnitStyle.css">
+	<script language="JavaScript" type="text/javascript" src="/jsunit/jsunit/app/jsUnitCore.js"></script>
+	<script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/util/Utils.js"></script>
+	<script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/Xap.js"></script>
+	<script language="JavaScript" type="text/javascript" src="_TestPluginRegistryImpl.js"></script>
+	
+	
+</head>
+
+<body>
+  	<script language="JavaScript" type="text/javascript">
+		Xap.bootstrap( "/jsunit" );
+  	</script>	
+</body>
+</html>
\ No newline at end of file

Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js Thu Jun 22 15:59:35 2006
@@ -0,0 +1,43 @@
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+function exposeTestFunctionNames() {
+   return ["testAddPluginDescription"];
+}
+
+	
+function testAddPluginDescription() {
+ 	var pluginRegistry = new PluginRegistryImpl(null);
+ 	var pluginString = HttpUtils.get( "/jsunit/testsrc/xap/taghandling/plugin.xml").responseText;
+ 	pluginRegistry.addPluginDescription(pluginString);
+ 	
+ 	var tagMapping = pluginRegistry.getTagMapping("objectDataSource", "http://nexaweb.com/data", "dataSources");
+ 	assertTrue("tag mapping for objectDataSource is com.nexaweb.plugin.data.bridge.DocumentDataSourceBridge",
+ 		tagMapping=="com.nexaweb.plugin.data.bridge.ObjectDataSourceBridge");
+ 		
+ 	tagMapping = pluginRegistry.getTagMapping("objectDataSource", "http://nexaweb.com/data1", "dataSources");
+ 	assertTrue("tag mapping for objectDataSource with wrong namespace is null",
+ 		tagMapping==null);
+ 		
+ 	tagMapping = pluginRegistry.getTagMapping("objectDataSource", "http://nexaweb.com/data", "dataSources1");
+ 	assertTrue("tag mapping for objectDataSource with wrong document is null",
+ 		tagMapping==null);
+ 		
+ 	tagMapping = pluginRegistry.getTagMapping("iteratorPlaceHolder",null,"xal");
+ 	assertTrue("tag mapping for iteratorPlaceHolder is special item",
+ 		tagMapping==PluginRegistryImpl.NO_MAPPED_CLASS);
+}
\ No newline at end of file

Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestPluginRegistryImpl.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html Thu Jun 22 15:59:35 2006
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
+	"http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <title>ClientSession Unit Tests</title>
+    <link rel="stylesheet" type="text/css" href="/jsunit/jsunit/css/jsUnitStyle.css">
+    <script language="JavaScript" type="text/javascript" src="/jsunit/jsunit/app/jsUnitCore.js"></script>
+	<script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/util/Utils.js"></script>
+	<script language="JavaScript" type="text/javascript" src="/jsunit/src/xap/Xap.js"></script>
+    <script language="JavaScript" type="text/javascript">
+        Xap.bootstrap( "/jsunit" );
+  	</script>
+</head>
+
+<body>
+    <script language="JavaScript" type="text/javascript">
+		function testUiDocumentHandlerMethods() {
+			var session = new ClientSession( "/xap" );
+		}
+    </script>
+</body>
+</html>
\ No newline at end of file

Propchange: incubator/xap/trunk/testsrc/xap/taghandling/_TestUiDocumentHandler.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml?rev=416494&view=auto
==============================================================================
--- incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml (added)
+++ incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml Thu Jun 22 15:59:35 2006
@@ -0,0 +1,49 @@
+<plugin>
+	<!-- mappings that apply to the document named "dataSources" -->
+	<tag-mappings namespace="http://nexaweb.com/data" document="dataSources">
+		<mapping class="com.nexaweb.plugin.data.bridge.DocumentDataSourceBridge"
+			name="documentDataSource"/>
+		<mapping class="com.nexaweb.plugin.data.bridge.ObjectDataSourceBridge"
+			name="objectDataSource"/>
+		<mapping class="com.nexaweb.plugin.data.bridge.DataSourceBridge"
+			name="dataSource"/>
+	</tag-mappings>
+	
+	<!-- mappings that apply to the document named "bindings" -->
+	<tag-mappings namespace="http://nexaweb.com/data" document="bindings">
+		<mapping class="com.nexaweb.plugin.data.bridge.BindingBridge"
+			name="binding"/>
+	</tag-mappings>
+	
+	<!-- mappings that apply to the document named "formatters" -->
+	<tag-mappings namespace="http://nexaweb.com/data" document="formatters">
+		<mapping class="com.nexaweb.plugin.data.bridge.FormatterBridge"
+			name="formatter"/>
+		<mapping class="com.nexaweb.plugin.data.bridge.MessageFormatterBridge"
+			name="messageFormatter"/>
+		<mapping class="com.nexaweb.plugin.data.bridge.DecimalFormatterBridge"
+			name="decimalFormatter"/>
+		<mapping class="com.nexaweb.plugin.data.bridge.CurrencyFormatterBridge"
+			name="currencyFormatter"/>
+		<mapping class="com.nexaweb.plugin.data.bridge.DateFormatterBridge"
+			name="dateFormatter"/>
+		<mapping
+			class="com.nexaweb.plugin.data.bridge.StringToDateFormatterBridge"
+			name="stringToDateFormatter"/>
+		<mapping class="com.nexaweb.plugin.data.bridge.FormatterChainBridge"
+			name="formatterChain"/>
+	</tag-mappings>
+	
+	<!-- mappings that apply to the ui document -->
+	<tag-mappings namespace="http://nexaweb.com/data">
+		<mapping class="com.nexaweb.plugin.data.bridge.IteratorBridge"
+			name="iterator"/>
+	</tag-mappings>
+	
+	<!-- The iteratorPlaceHolder element is used to keep track of the spot
+		an iterator with an empty dataset will be contributing to. -->
+	<unmapped-tags>
+		<mapping name="iteratorPlaceHolder"/>
+	</unmapped-tags>
+	
+</plugin>

Propchange: incubator/xap/trunk/testsrc/xap/taghandling/plugin.xml
------------------------------------------------------------------------------
    svn:eol-style = native