Skip to main content

This CGIT instance is deprecated, and repositories have been moved to Gitlab or Github. See the repository descriptions for specific locations.

summaryrefslogblamecommitdiffstats
blob: 6c5c4e71db1e2e4d2b25a71f870d0a0dac4c9daa (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                                                                
                                                       







                                                                                 
                                                           
 
                    
                               
                                   
                           
                         


                           
                     

                       
                                        
                                          



                                                  
                                         
                                                
                                                                       




                                                                                            

                                                                                                     
                                                                
                                                                    
                                                                      
                                                                     

                                                                           

                                                  

                                                         

                                                            
                                                  
                                                   
                                                                                 


                                                                                             
                                                              


                                                                                    
                                                                                
                                                                          

                                                     
                                                  

                                                                     
                                                                  
 
                                                                   

                                                                                                                                                       





                                                                                     
                                                                                            


                                                                            
                                                                                                                                         





                                                                                                                                                                               



                                                                                                                                                                














                                                                                                                                         






                                                                                                                                                                 









                                                                                                                                          
                                                                                         

                 













                                                                                     

                                                                                                                                        


                                                                                                                                                                             
                 
























                                                                                                                                                                                      
                                 

                                                                                                                     

                                 


                                                                                                                                                                  

                 





                                                                                                                 




                                                                                  

                                                                                     
                   

                                                                                                                                                                                       
                                                   

                                                   
                                                                                                  
                                                                            
                                                                                                          
                                                                                                                                                                              





                                                                           
                                                                                                                              
                                                                                                                                                             





                                                                          
                                                    
                         
 
                                                                       

                                                                                      
                                                      




                                                                                                                                                                         
                                                    
                                                                                                                                                                                         

                                                                                                  


                                                                                                

                                                                                                








                                                                                                  
                                           

                                                                                  







                                                                                                                                             
                                                 




                                                                                              
                                                                    
                                         

                                                                                                      
                                                                                                           

                                                                                                                                      



                                                                                                    
                                                                                                                                             
                                                                                                                                           

                                                 


                                                                 
                                                                                                                         



                                 

                                                                                                                                                                                         

                                             











                                                                                                                                            
                                                                                                          

                                                                                                                                                          
                                                                                             
                                                                                     


                                                                      
                                                                              

                                                 
                                                                                                                                 
                                                                                            
                                                                                                                      
                                                                                     



                                                                                                                            
                                                                 

                                                                                                                                       
                                                                 
                                                                                                                        

                                                                              
                                                         



                                                 





                                                                               

                                                                                                                                                                                     




                                               
                                                                          

                                                                            
                                                                                                           
                                                                                
                                                                                                          
                                                                                                














                                                                                                                                   
                                                                                                                
                                                                                          
                                                                                                                                
                                                                                            
                                                                                                                             
                                                                                               
                                                                                                                                







                                                                          
                                                                                                       
                                                                                                                    
                         
                                                                                                                  
                                                                                                                                      


                         

































                                                                                                                                                  





                                                                                  
                                                                                                               














                                                                                                                                                          
 
                                                                                    


                                                                                                                                                              









                                                                                        
                                             
 



                                                                                                    








                                                                                                                                                                

                 
                                                              
                                                                                    

                 

                                                                                                 

                 
                   

                                                                        

                                        

                                                                  
                                                     

                                                                                            
                                              
                                                                         



                                                                                                                                                       



                                                                                                                                





                                                          







                                           
                                       








                                                      
                 
         
 


                                              

         
                                                                                                                                                                           
                                                                                                                                                                              


                                                                                  
 
                                               


                                                     
 


                                                          
 










                                                            














                                                                                 

                                      












                                                                           

                                                                                 












                                                                           
 
                                                               
 
                                                                                  



                                               
                                            
 

                                                         
                                                       
                                                      
 



                                               

                                            
                                                

                                        
 




                                       










                                                                                                                      
                                                                                                            






                                         




                                                                                  







                                                                                                          
                 

                                                                                                                             


           





                                                        
                                                         
                                                                    
                                                                           
                                  












                                                                                                             






                                                                                                                                                          
                                 










                                                                                                                                                 












                                                                                                      
                                                                                                  





                                                                                      



                           



















































                                                                                                                                                   
           











                                                                            
                                                 










                                                                                                             
                                                 









                                                                                                                                                      
           



                                                                                  
           
                  


                                          

                                                                                                    


                                            


                                    


















                                                                                  








                                                                                                          
                                                






                                                     
           













                                                



                                                  



                                                                                     








                                                          
 
                               
                                                                                              

                                         




                                                                                                                                        
                                                                           
                                                                                                                       





                                                                                                                             



                                                                                                                                                   











                                                                                                                                                                                                                                     
           

                                                        
           
                                                           

                                       
                                                





                                                                                  
                                                                           











                                                      
                                                 

                                                               
                               




                                                                                       
                                                                       





                                                                                            
                                                                                          





                                                                                          
                                                                                  




                              







                                                                                       
                         
                 


           
                                                                            
                                     
           












                                                                                                       

                              
                                                                               







                                                                                                                                                      


                                                                                      
                                         
                                 

                         
                             





                                                                                                               
                                        


                                            
                                                             

                                                                                                            
                                 

                                                                                                         
         
 
/*******************************************************************************
 * Copyright (c) 2004, 2007 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jst.jsp.core.internal.contentmodel.tld;

import java.io.File;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jst.jsp.core.internal.Logger;
import org.eclipse.jst.jsp.core.internal.contentmodel.TaglibController;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.JSP11TLDNames;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.JSP12TLDNames;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.JSP20TLDNames;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.TLDDocument;
import org.eclipse.jst.jsp.core.internal.contentmodel.tld.provisional.TLDElementDeclaration;
import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache;
import org.eclipse.jst.jsp.core.internal.contenttype.DeploymentDescriptorPropertyCache.PropertyGroup;
import org.eclipse.jst.jsp.core.internal.parser.JSPSourceParser;
import org.eclipse.jst.jsp.core.internal.provisional.JSP12Namespace;
import org.eclipse.jst.jsp.core.internal.regions.DOMJSPRegionContexts;
import org.eclipse.jst.jsp.core.internal.util.FacetModuleCoreSupport;
import org.eclipse.jst.jsp.core.internal.util.FileContentCache;
import org.eclipse.jst.jsp.core.internal.util.ZeroStructuredDocumentRegion;
import org.eclipse.jst.jsp.core.taglib.IJarRecord;
import org.eclipse.jst.jsp.core.taglib.ITLDRecord;
import org.eclipse.jst.jsp.core.taglib.ITagDirRecord;
import org.eclipse.jst.jsp.core.taglib.ITaglibIndexDelta;
import org.eclipse.jst.jsp.core.taglib.ITaglibIndexListener;
import org.eclipse.jst.jsp.core.taglib.ITaglibRecord;
import org.eclipse.jst.jsp.core.taglib.IURLRecord;
import org.eclipse.jst.jsp.core.taglib.TaglibIndex;
import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverPlugin;
import org.eclipse.wst.sse.core.internal.ltk.parser.BlockMarker;
import org.eclipse.wst.sse.core.internal.ltk.parser.StructuredDocumentRegionHandler;
import org.eclipse.wst.sse.core.internal.ltk.parser.StructuredDocumentRegionHandlerExtension;
import org.eclipse.wst.sse.core.internal.ltk.parser.TagMarker;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionCollection;
import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList;
import org.eclipse.wst.sse.core.internal.util.Assert;
import org.eclipse.wst.sse.core.internal.util.Debug;
import org.eclipse.wst.sse.core.utils.StringUtils;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;

public class TLDCMDocumentManager implements ITaglibIndexListener {

	protected class DirectiveStructuredDocumentRegionHandler implements StructuredDocumentRegionHandler, StructuredDocumentRegionHandlerExtension {
		/**
		 * Adds a block tagname (fully namespace qualified) into the list of
		 * block tag names for the parser. The marker
		 * IStructuredDocumentRegion along with position cues during reparses
		 * allow the JSPSourceParser to enable/ignore the tags as blocks.
		 */
		protected void addBlockTag(String tagnameNS, ITextRegionCollection marker) {
			if (getParser() == null)
				return;
			if (getParser().getBlockMarker(tagnameNS) == null) {
				getParser().addBlockMarker(new BlockMarker(tagnameNS, marker, DOMRegionContext.BLOCK_TEXT, true, false));
				if (_debug) {
					System.out.println("TLDCMDocumentManager added block marker: " + tagnameNS + "@" + marker.getStartOffset()); //$NON-NLS-2$//$NON-NLS-1$
				}
			}
		}

		protected void addTaglibTracker(String prefix, String uri, IStructuredDocumentRegion anchorStructuredDocumentRegion, CMDocument tldCMDocument) {
			getTaglibTrackers().add(new TaglibTracker(uri, prefix, tldCMDocument, anchorStructuredDocumentRegion));
		}

		/**
		 * Enables a TLD owning the given prefix loaded from the given URI at
		 * the anchorStructuredDocumentRegion. The list of
		 * additionalCMDocuments will claim to not know any of its tags at
		 * positions earlier than that IStructuredDocumentRegion's position.
		 * 
		 * For taglib directives, the taglib is the anchor while taglibs
		 * registered through include directives use the parent document's
		 * include directive as their anchor.
		 * 
		 * @param prefix
		 * @param uri
		 * @param anchorStructuredDocumentRegion
		 */
		protected void enableTaglibFromURI(String prefix, String uri, IStructuredDocumentRegion anchorStructuredDocumentRegion) {
			enableTags(prefix, uri, anchorStructuredDocumentRegion);
			if (_debug) {
				System.out.println("TLDCMDocumentManager registered a tracker for " + uri + " with prefix " + prefix); //$NON-NLS-2$//$NON-NLS-1$
			}
		}

		private void enableTags(String prefix, String uri, IStructuredDocumentRegion anchorStructuredDocumentRegion) {
			if (prefix == null || uri == null || bannedPrefixes.contains(prefix))
				return;
			// Try to load the CMDocument for this URI
			CMDocument tld = getCMDocument(uri);
			if (tld == null || !(tld instanceof TLDDocument)) {
				if (_debug) {
					System.out.println("TLDCMDocumentManager failed to create a CMDocument for " + uri); //$NON-NLS-1$
				}
				return;
			}
			registerTaglib(prefix, uri, anchorStructuredDocumentRegion, tld);
		}

		/**
		 * Enables a TLD owning the given prefix loaded from the given URI at
		 * the anchorStructuredDocumentRegion. The list of
		 * additionalCMDocuments will claim to not know any of its tags at
		 * positions earlier than that IStructuredDocumentRegion's position.
		 * 
		 * For taglib directives, the taglib is the anchor while taglibs
		 * registered through include directives use the parent document's
		 * include directive as their anchor.
		 * 
		 * @param prefix
		 * @param uri
		 * @param taglibStructuredDocumentRegion
		 */
		protected void enableTagsInDir(String prefix, String tagdir, IStructuredDocumentRegion anchorStructuredDocumentRegion) {
			enableTags(prefix, tagdir, anchorStructuredDocumentRegion);
			if (_debug) {
				System.out.println("TLDCMDocumentManager registered a tracker for directory" + tagdir + " with prefix " + prefix); //$NON-NLS-2$//$NON-NLS-1$
			}
		}
		
		protected void processRegionCollection(ITextRegionCollection regionCollection, IStructuredDocumentRegion anchorStructuredDocumentRegion, JSPSourceParser textSource) {
			/*
			 * Would test > 1, but since we only care if there are 8 (<%@,
			 * taglib, uri, =, where, prefix, =, what) [or 4 for include
			 * directives]
			 */
			if (regionCollection.getNumberOfRegions() > 4 && regionCollection.getRegions().get(1).getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME) {
				ITextRegion name = regionCollection.getRegions().get(1);
				boolean taglibDetected = false;
				boolean taglibDirectiveDetected = false;
				boolean includeDetected = false;
				boolean includeDirectiveDetected = false;
				int startOffset = regionCollection.getStartOffset(name);
				int textLength = name.getTextLength();

				taglibDetected = textSource.regionMatches(startOffset, textLength, JSP12TLDNames.TAGLIB);
				if (!taglibDetected)
					taglibDirectiveDetected = textSource.regionMatches(startOffset, textLength, JSP12Namespace.ElementName.DIRECTIVE_TAGLIB);
				if (!taglibDirectiveDetected)
					includeDetected = textSource.regionMatches(startOffset, textLength, JSP12TLDNames.INCLUDE);
				if (!includeDetected)
					includeDirectiveDetected = textSource.regionMatches(startOffset, textLength, JSP12Namespace.ElementName.DIRECTIVE_INCLUDE);
				if (taglibDetected || taglibDirectiveDetected) {
					processTaglib(regionCollection, anchorStructuredDocumentRegion, textSource);
				}
				else if (includeDetected || includeDirectiveDetected) {
					processInclude(regionCollection, anchorStructuredDocumentRegion, textSource);
				}
			}
			else if (regionCollection.getNumberOfRegions() > 1 && DOMRegionContext.XML_TAG_OPEN.equals(regionCollection.getFirstRegion().getType())) {
				processXMLStartTag(regionCollection, anchorStructuredDocumentRegion, textSource);
			}			
		}

		public void nodeParsed(IStructuredDocumentRegion structuredDocumentRegion) {
			if (!preludesHandled) {
				handlePreludes();
				preludesHandled = true;
			}
			processRegionCollection(structuredDocumentRegion, structuredDocumentRegion, getParser());
		}

		/**
		 * Process an include directive found by the textSource parser and
		 * anchor any taglibs found within at the
		 * anchorStructuredDocumentRegion. Includes use the including file as
		 * the point of reference, not necessarily the "top" file.
		 */
		protected void processInclude(ITextRegionCollection includeDirectiveCollection, IStructuredDocumentRegion anchorStructuredDocumentRegion, JSPSourceParser textSource) {
			ITextRegionList regions = includeDirectiveCollection.getRegions();
			String includedFile = null;
			boolean isFilename = false;
			try {
				for (int i = 2; includedFile == null && i < regions.size(); i++) {
					ITextRegion region = regions.get(i);
					if (region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) {
						if (textSource.regionMatches(includeDirectiveCollection.getStartOffset(region), region.getTextLength(), JSP12TLDNames.FILE)) {
							isFilename = true;
						}
						else {
							isFilename = false;
						}
					}
					else if (isFilename && region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
						includedFile = textSource.getText(includeDirectiveCollection.getStartOffset(region), region.getTextLength());
						isFilename = false;
					}
				}
			}
			catch (StringIndexOutOfBoundsException sioobExc) {
				// nothing to be done
				includedFile = null;
			}

			if (fProcessIncludes && includedFile != null) {
				// strip any extraneous quotes and white space
				includedFile = StringUtils.strip(includedFile).trim();
				IPath filePath = null;
				if (getIncludes().isEmpty())
					filePath = FacetModuleCoreSupport.resolve(TaglibController.getFileBuffer(TLDCMDocumentManager.this).getLocation(), includedFile);
				else
					filePath = FacetModuleCoreSupport.resolve((IPath) getIncludes().peek(), includedFile);

				// check for "loops"
				if (filePath != null && !getIncludes().contains(filePath) && !filePath.equals(TaglibController.getFileBuffer(TLDCMDocumentManager.this).getLocation())) {
					/*
					 * Prevent slow performance when editing scriptlet part of
					 * the JSP by only processing includes if they've been
					 * modified. The IncludeHelper remembers any CMDocuments
					 * created from the files it parses. Caching the URI and
					 * prefix/tagdir allows us to just enable the CMDocument
					 * when the previously parsed files.
					 * 
					 * REMAINING PROBLEM: fTLDCMReferencesMap does not map
					 * from a fragment's path and also include all of the CM
					 * references in fragments that *it* includes. The
					 * fragments that it includes won't have its CM references
					 * loaded, but then we'd need to record the URI and
					 * location of the included fragment to resolve them
					 * correctly, modifying enableTaglib() to also take a base
					 * path and resolve the URI appropriately.
					 */
					if (hasAnyIncludeBeenModified(filePath)) {
						getIncludes().push(filePath);

						IncludeHelper includeHelper = new IncludeHelper(anchorStructuredDocumentRegion, getParser());
						includeHelper.parse(filePath);
						List references = includeHelper.taglibReferences;
						fTLDCMReferencesMap.put(filePath, references);
						for (int i = 0; references != null && i < references.size(); i++) {
							TLDCMDocumentReference reference = (TLDCMDocumentReference) references.get(i);
							getParser().addNestablePrefix(new TagMarker(reference.prefix + ":")); //$NON-NLS-1$
						}
						/*
						 * TODO: walk up the include hierarchy and add
						 * these references to each of the parents?
						 */

						getIncludes().pop();
					}
					else {
						// Add from that saved list of uris/prefixes/documents
						List references = (List) fTLDCMReferencesMap.get(filePath);
						for (int i = 0; references != null && i < references.size(); i++) {
							TLDCMDocumentReference reference = (TLDCMDocumentReference) references.get(i);
							/*
							 * The uri might not be resolved properly if
							 * relative to the JSP fragment.
							 */
							enableTaglibFromURI(reference.prefix, reference.uri, anchorStructuredDocumentRegion);
							getParser().addNestablePrefix(new TagMarker(reference.prefix + ":")); //$NON-NLS-1$
						}
					}
				}
				else {
					if (Debug.debugTokenizer)
						System.out.println("LOOP IN @INCLUDES FOUND: " + filePath); //$NON-NLS-1$
				}
			}
		}

		protected void processXMLStartTag(ITextRegionCollection startTagRegionCollection, IStructuredDocumentRegion anchorStructuredDocumentRegion, JSPSourceParser textSource) {
			ITextRegionList regions = startTagRegionCollection.getRegions();
			String uri = null;
			String prefix = null;
			boolean isTaglibValue = false;
			// skip the first two, they're the open bracket and name
			for (int i = 2; i < regions.size(); i++) {
				ITextRegion region = regions.get(i);
				if (region instanceof ITextRegionCollection) {
					// Handle nested directives
					processRegionCollection((ITextRegionCollection) region, anchorStructuredDocumentRegion, textSource);
				}
				else {
					// Handle xmlns:xxx=yyy
					int regionStartOffset = startTagRegionCollection.getStartOffset(region);
					int regionTextLength = region.getTextLength();
					if (region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) {
						if (regionTextLength > XMLNS_LENGTH && textSource.regionMatches(regionStartOffset, XMLNS_LENGTH, XMLNS)) {
							prefix = textSource.getText(regionStartOffset + XMLNS_LENGTH, regionTextLength - XMLNS_LENGTH);
							if (!bannedPrefixes.contains(prefix))
								isTaglibValue = true;
						}
						else {
							prefix = null;
							isTaglibValue = false;
						}
					}
					else if (isTaglibValue && region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
						if (prefix != null && prefix.length() > 0) {
							uri = textSource.getText(regionStartOffset, regionTextLength);
							uri = StringUtils.strip(uri);
							int uriLength = uri.length();
							if (uri != null && uriLength > 0) {
								if (uriLength > URN_TLD_LENGTH && uri.startsWith(URN_TLD)) {
									uri = uri.substring(URN_TLD_LENGTH);
								}
								else if (uriLength > URN_TAGDIR_LENGTH && uri.startsWith(URN_TAGDIR)) {
									uri = uri.substring(URN_TAGDIR_LENGTH);
								}
								enableTags(prefix, uri, anchorStructuredDocumentRegion);
								uri = null;
								prefix = null;
							}
						}
					}
				}
			}
		}

		/**
		 * Pulls the URI and prefix from the given taglib directive
		 * IStructuredDocumentRegion and makes sure the tags are known.
		 */
		protected void processTaglib(ITextRegionCollection taglibDirectiveCollection, IStructuredDocumentRegion anchorStructuredDocumentRegion, JSPSourceParser textSource) {
			ITextRegionList regions = taglibDirectiveCollection.getRegions();
			String uri = null;
			String prefix = null;
			String tagdir = null;
			String attrName = null;
			try {
				for (int i = 2; i < regions.size(); i++) {
					ITextRegion region = regions.get(i);
					// remember attribute name
					int startOffset = taglibDirectiveCollection.getStartOffset(region);
					int textLength = region.getTextLength();
					if (region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) {
						// String name = textSource.getText(startOffset,
						// textLength);
						if (textSource.regionMatches(startOffset, textLength, JSP11TLDNames.PREFIX)) {
							attrName = JSP11TLDNames.PREFIX;
						}
						else if (textSource.regionMatches(startOffset, textLength, JSP12TLDNames.URI)) {
							attrName = JSP11TLDNames.URI;
						}
						else if (textSource.regionMatches(startOffset, textLength, JSP20TLDNames.TAGDIR)) {
							attrName = JSP20TLDNames.TAGDIR;
						}
						else {
							attrName = null;
						}
					}
					// process value
					else if (region.getType() == DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE) {
						if (JSP11TLDNames.PREFIX.equals(attrName))
							prefix = StringUtils.strip(textSource.getText(startOffset, textLength));
						else if (JSP11TLDNames.URI.equals(attrName))
							uri = StringUtils.strip(textSource.getText(startOffset, textLength));
						else if (JSP20TLDNames.TAGDIR.equals(attrName))
							tagdir = StringUtils.strip(textSource.getText(startOffset, textLength));
					}
				}
			}
			catch (StringIndexOutOfBoundsException sioobExc) {
				// nothing to be done
				uri = null;
				prefix = null;
			}
			if (uri != null && prefix != null && uri.length() > 0 && prefix.length() > 0) {
				enableTaglibFromURI(prefix, StringUtils.strip(uri), anchorStructuredDocumentRegion);
			}
			else if (tagdir != null && prefix != null && tagdir.length() > 0 && prefix.length() > 0) {
				enableTagsInDir(StringUtils.strip(prefix), StringUtils.strip(tagdir), anchorStructuredDocumentRegion);
			}
		}

		private void registerTaglib(String prefix, String uri, IStructuredDocumentRegion anchorStructuredDocumentRegion, CMDocument tld) {
			CMNamedNodeMap elements = tld.getElements();
			/*
			 * Go through the CMDocument for any tags that must be marked as
			 * block tags starting at the anchoring IStructuredDocumentRegion.
			 * As the document is edited and the IStructuredDocumentRegion
			 * moved around, the block tag enablement will automatically
			 * follow it.
			 */
			for (int i = 0; i < elements.getLength(); i++) {
				TLDElementDeclaration ed = (TLDElementDeclaration) elements.item(i);
				if (ed.getBodycontent() == JSP12TLDNames.CONTENT_TAGDEPENDENT)
					addBlockTag(prefix + ":" + ed.getNodeName(), anchorStructuredDocumentRegion); //$NON-NLS-1$
			}
			/*
			 * Since modifications to StructuredDocumentRegions adjacent to a
			 * taglib directive can cause that IStructuredDocumentRegion to be
			 * reported, filter out any duplicated URIs. When the taglib is
			 * actually modified, a full rebuild will occur and no duplicates
			 * will/should be found.
			 */
			boolean doTrack = true;
			List trackers = getTaglibTrackers();
			for (int i = 0; i < trackers.size(); i++) {
				TaglibTracker tracker = (TaglibTracker) trackers.get(i);
				if (tracker.getPrefix().equals(prefix) && tracker.getURI().equals(uri)) {
					doTrack = false;
				}
			}
			if (doTrack) {
				addTaglibTracker(prefix, uri, anchorStructuredDocumentRegion, tld);
			}
		}

		private void resetBlockTags() {
			if (getParser() == null)
				return;
			Iterator names = getParser().getBlockMarkers().iterator();
			while (names.hasNext()) {
				BlockMarker marker = (BlockMarker) names.next();
				if (!marker.isGlobal() && marker.getContext() == DOMRegionContext.BLOCK_TEXT) {
					if (_debug) {
						System.out.println("TLDCMDocumentManager removing block tag named: " + marker.getTagName()); //$NON-NLS-1$
					}
					names.remove();
				}
			}
		}

		public void resetNodes() {
			if (Debug.debugTaglibs)
				System.out.println(getClass().getName() + ": resetting"); //$NON-NLS-1$
			getIncludes().clear();
			resetBlockTags();
			resetTaglibTrackers();
		}

		public void setStructuredDocument(IStructuredDocument newDocument) {
			Assert.isTrue(newDocument != null, "null document"); //$NON-NLS-1$
			Assert.isTrue(newDocument.getParser() != null, "null document parser"); //$NON-NLS-1$
			Assert.isTrue(newDocument.getParser() instanceof JSPSourceParser, "can only listen to document with a JSPSourceParser"); //$NON-NLS-1$
			getSourceParser().removeStructuredDocumentRegionHandler(this);
			setSourceParser((JSPSourceParser) newDocument.getParser());
			getSourceParser().addStructuredDocumentRegionHandler(this);
		}
	}

	protected class IncludeHelper extends DirectiveStructuredDocumentRegionHandler {
		protected IStructuredDocumentRegion fAnchor = null;
		protected JSPSourceParser fLocalParser = null;
		protected JSPSourceParser fParentParser = null;
		List taglibReferences = null;

		public IncludeHelper(IStructuredDocumentRegion anchor, JSPSourceParser rootParser) {
			super();
			fAnchor = anchor;
			fParentParser = rootParser;
			taglibReferences = new ArrayList(0);
		}

		protected void addTaglibTracker(String prefix, String uri, IStructuredDocumentRegion anchorStructuredDocumentRegion, CMDocument tldCMDocument) {
			super.addTaglibTracker(prefix, uri, anchorStructuredDocumentRegion, tldCMDocument);
			TLDCMDocumentReference reference = new TLDCMDocumentReference();
			reference.prefix = prefix;
			reference.uri = uri;
			taglibReferences.add(reference);
		}

		protected String getContents(IPath filePath) {
			return FileContentCache.getInstance().getContents(filePath);
		}

		public void nodeParsed(IStructuredDocumentRegion structuredDocumentRegion) {
			processRegionCollection(structuredDocumentRegion, fAnchor, fLocalParser);
		}

		/**
		 * @param path -
		 *            the fullpath for the resource to be parsed
		 */
		void parse(IPath path) {
			JSPSourceParser p = new JSPSourceParser();
			fLocalParser = p;
			String s = getContents(path);
			// Should we consider preludes on this segment?
			fLocalParser.addStructuredDocumentRegionHandler(IncludeHelper.this);
			fLocalParser.reset(s);
			List blockTags = fParentParser.getBlockMarkers();
			for (int i = 0; i < blockTags.size(); i++) {
				BlockMarker marker = (BlockMarker) blockTags.get(i);
				fLocalParser.addBlockMarker(new BlockMarker(marker.getTagName(), null, marker.getContext(), marker.isCaseSensitive()));
			}
			TagMarker[] knownPrefixes = (TagMarker[]) fParentParser.getNestablePrefixes().toArray(new TagMarker[0]);
			for (int i = 0; i < knownPrefixes.length; i++) {
				fLocalParser.addNestablePrefix(new TagMarker(knownPrefixes[i].getTagName(), null));
			}
			// force parse
			fLocalParser.getDocumentRegions();
			fLocalParser = null;
		}

		public void resetNodes() {
		}
	}

	/**
	 * An entry in the shared cache map
	 */
	static class TLDCacheEntry {
		CMDocument document;
		long modificationStamp;
		int referenceCount;
	}

	private static class TLDCMDocumentDescriptor {
		Object cacheKey;
		CMDocument document;

		TLDCMDocumentDescriptor() {
			super();
		}
	}

	private class TLDCMDocumentReference {
		String prefix;
		String uri;
	}

	static final boolean _debug = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/tldcmdocument/manager")); //$NON-NLS-1$ //$NON-NLS-2$
	static final boolean _debugCache = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/tldcmdocument/cache")); //$NON-NLS-1$ //$NON-NLS-2$
	// will hold the prefixes banned by the specification; taglibs may not use
	// them
	protected static List bannedPrefixes = null;

	private static Hashtable fCache = null;
	final String XMLNS = "xmlns:"; //$NON-NLS-1$ 
	final String URN_TAGDIR = "urn:jsptagdir:";
	final String URN_TLD = "urn:jsptld:";

	final int XMLNS_LENGTH = XMLNS.length();
	final int URN_TAGDIR_LENGTH = URN_TAGDIR.length();
	final int URN_TLD_LENGTH = URN_TLD.length();

	static {
		bannedPrefixes = new ArrayList(7);
		bannedPrefixes.add("jsp"); //$NON-NLS-1$
		bannedPrefixes.add("jspx"); //$NON-NLS-1$
		bannedPrefixes.add("java"); //$NON-NLS-1$
		bannedPrefixes.add("javax"); //$NON-NLS-1$
		bannedPrefixes.add("servlet"); //$NON-NLS-1$
		bannedPrefixes.add("sun"); //$NON-NLS-1$
		bannedPrefixes.add("sunw"); //$NON-NLS-1$
	}

	/**
	 * Gets all of the known documents.
	 * 
	 * @return Returns a Hashtable of either TLDCacheEntrys or WeakReferences
	 *         to TLD CMDocuments
	 */
	public static Hashtable getSharedDocumentCache() {
		if (fCache == null) {
			fCache = new Hashtable();
		}
		return fCache;
	}


	public static Object getUniqueIdentifier(ITaglibRecord reference) {
		if (reference == null)
			return null;
		Object identifier = null;
		switch (reference.getRecordType()) {
			case (ITaglibRecord.TLD) : {
				ITLDRecord record = (ITLDRecord) reference;
				identifier = record.getPath();
			}
				break;
			case (ITaglibRecord.JAR) : {
				IJarRecord record = (IJarRecord) reference;
				identifier = record.getLocation();
			}
				break;
			case (ITaglibRecord.TAGDIR) : {
				ITagDirRecord record = (ITagDirRecord) reference;
				identifier = record.getPath();
			}
				break;
			case (ITaglibRecord.URL) : {
				IURLRecord record = (IURLRecord) reference;
				identifier = record.getURL();
			}
				break;
			default :
				identifier = reference;
				break;
		}
		return identifier;
	}

	private CMDocumentFactoryTLD fCMDocumentBuilder = null;

	private DirectiveStructuredDocumentRegionHandler fDirectiveHandler = null;

	/**
	 * The locally-know list of CMDocuments
	 */
	private Hashtable fDocuments = null;

	// timestamp cache to prevent excessive reparsing
	// of included files
	// IPath (filepath) > Long (modification stamp)
	HashMap fInclude2TimestampMap = new HashMap();

	private Stack fIncludes = null;

	private JSPSourceParser fParser = null;

	private List fTaglibTrackers = null;

	Map fTLDCMReferencesMap = new HashMap();
	boolean fProcessIncludes = true;
	boolean preludesHandled = false;

	public TLDCMDocumentManager() {
		super();
	}

	public void clearCache() {
		if (_debugCache) {
			System.out.println("TLDCMDocumentManager cleared its private CMDocument cache"); //$NON-NLS-1$
		}
		for (Iterator iter = getDocuments().keySet().iterator(); iter.hasNext();) {
			Object key = iter.next();
			synchronized (getSharedDocumentCache()) {
				Object o = getSharedDocumentCache().get(key);
				if (o instanceof TLDCacheEntry) {
					TLDCacheEntry entry = (TLDCacheEntry) o;
					entry.referenceCount--;
					if (entry.referenceCount <= 0) {
						getSharedDocumentCache().put(key, new WeakReference(entry));
					}
				}
			}
		}
	}

	/**
	 * Derives an unique cache key for the give URI. The URI is "resolved" and
	 * a unique value generated from the result. This ensures that two
	 * different relative references from different files do not have
	 * overlapping TLD records in the shared cache if they don't resolve to
	 * the same TLD.
	 * 
	 * @param uri
	 * @return
	 */
	protected Object getCacheKey(String uri) {
		ITaglibRecord record = TaglibIndex.resolve(getCurrentParserPath().toString(), uri, false);
		if (record != null) {
			return getUniqueIdentifier(record);
		}
		String location = URIResolverPlugin.createResolver().resolve(getCurrentBaseLocation().toString(), null, uri);
		return location;
	}

	/**
	 * Return the CMDocument at the uri (cached)
	 */
	protected CMDocument getCMDocument(String uri) {
		if (uri == null || uri.length() == 0)
			return null;
		String reference = uri;
		Object cacheKey = getCacheKey(reference);
		long lastModified = getModificationStamp(reference);
		CMDocument doc = (CMDocument) getDocuments().get(cacheKey);
		if (doc == null) {
			/*
			 * If hasn't been moved into the local table, do so and increment
			 * the count. A local URI reference can be different depending on
			 * the file from which it was referenced. Use a computed key to
			 * keep them straight.
			 */
			Object o = getSharedDocumentCache().get(cacheKey);
			if (o != null) {
				if (o instanceof TLDCacheEntry) {
					TLDCacheEntry entry = (TLDCacheEntry) o;
					if (_debugCache) {
						System.out.println("TLDCMDocument cache hit on " + cacheKey);
					}
					if (entry != null && entry.modificationStamp != IResource.NULL_STAMP && entry.modificationStamp >= lastModified) {
						doc = entry.document;
						entry.referenceCount++;
					}
					else {
						getSharedDocumentCache().remove(cacheKey);
					}
				}
				else if (o instanceof Reference) {
					TLDCacheEntry entry = (TLDCacheEntry) ((Reference) o).get();
					if (entry != null) {
						if (entry.modificationStamp != IResource.NULL_STAMP && entry.modificationStamp >= lastModified) {
							doc = entry.document;
							entry.referenceCount = 1;
							getSharedDocumentCache().put(cacheKey, entry);
						}
					}
					else {
						getSharedDocumentCache().remove(cacheKey);
					}
				}
			}
			/* No document was found cached, create a new one and share it */
			if (doc == null) {
				if (_debugCache) {
					System.out.println("TLDCMDocument cache miss on " + cacheKey);
				}
				TLDCMDocumentDescriptor descriptor = loadTaglib(reference);
				if (descriptor != null) {
					TLDCacheEntry entry = new TLDCacheEntry();
					doc = entry.document = descriptor.document;
					entry.referenceCount = 1;
					entry.modificationStamp = getModificationStamp(reference);
					getSharedDocumentCache().put(cacheKey, entry);
				}
			}
			if (doc != null) {
				getDocuments().put(cacheKey, doc);
			}
		}
		return doc;
	}

	private long getModificationStamp(String reference) {
		ITaglibRecord record = TaglibIndex.resolve(getCurrentParserPath().toString(), reference, false);
		long modificationStamp = IResource.NULL_STAMP;
		if (record != null) {
			switch (record.getRecordType()) {
				case (ITaglibRecord.TLD) : {
					IFile tldfile = ResourcesPlugin.getWorkspace().getRoot().getFile(((ITLDRecord) record).getPath());
					if (tldfile.isAccessible()) {
						modificationStamp = tldfile.getModificationStamp();
					}
				}
					break;
				case (ITaglibRecord.JAR) : {
					File jarfile = new File(((IJarRecord) record).getLocation().toOSString());
					if (jarfile.exists()) {
						try {
							modificationStamp = jarfile.lastModified();
						}
						catch (SecurityException e) {
							modificationStamp = IResource.NULL_STAMP;
						}
					}
				}
					break;
				case (ITaglibRecord.TAGDIR) : {
					IFolder tagFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(((ITagDirRecord) record).getPath());
					if (tagFolder.isAccessible()) {
						IResource[] members;
						try {
							members = tagFolder.members();
							for (int i = 0; i < members.length; i++) {
								modificationStamp = Math.max(modificationStamp, members[i].getModificationStamp());
							}
						}
						catch (CoreException e) {
							modificationStamp = IResource.NULL_STAMP;
						}
					}
				}
					break;
				case (ITaglibRecord.URL) : {
					modificationStamp = IResource.NULL_STAMP;
				}
					break;
				default :
					break;
			}
		}
		return modificationStamp;
	}


	/**
	 * Gets the cMDocumentBuilder.
	 * 
	 * @return Returns a CMDocumentFactoryTLD, since it has more builder
	 *         methods
	 */
	protected CMDocumentFactoryTLD getCMDocumentBuilder() {
		if (fCMDocumentBuilder == null)
			fCMDocumentBuilder = new CMDocumentFactoryTLD();
		return fCMDocumentBuilder;
	}

	public List getCMDocumentTrackers(int offset) {
		List validDocs = new ArrayList();
		Iterator alldocs = getTaglibTrackers().iterator();
		while (alldocs.hasNext()) {
			TaglibTracker aTracker = (TaglibTracker) alldocs.next();
			if (aTracker.getStructuredDocumentRegion().getStartOffset() < offset || offset < 0) {
				validDocs.add(aTracker);
			}
		}
		return validDocs;
	}

	public List getCMDocumentTrackers(String prefix, int offset) {
		List validDocs = new ArrayList();
		Iterator alldocs = getTaglibTrackers().iterator();
		while (alldocs.hasNext()) {
			TaglibTracker aTracker = (TaglibTracker) alldocs.next();
			if ((aTracker.getStructuredDocumentRegion().getStartOffset() < offset || offset < 0) && aTracker.getPrefix().equals(prefix)) {
				validDocs.add(aTracker);
			}
		}
		return validDocs;
	}

	/**
	 * Return the filesystem location in the current parser. This method is
	 * called while recursing through included fragments, so it much check the
	 * include stack. The filesystem location is needed for common URI
	 * resolution in case the Taglib Index doesn't know the URI being loaded.
	 * 
	 * @return
	 */
	IPath getCurrentBaseLocation() {
		IPath baseLocation = null;
		IPath path = getCurrentParserPath();
		baseLocation = ResourcesPlugin.getWorkspace().getRoot().getFile(path).getLocation();
		if (baseLocation == null) {
			baseLocation = path;
		}
		return baseLocation;
	}

	/**
	 * Return the path used in the current parser. This method is called while
	 * recursing through included fragments, so it much check the include
	 * stack.
	 * 
	 * @return
	 */
	IPath getCurrentParserPath() {
		IPath path = null;
		if (!getIncludes().isEmpty()) {
			path = (IPath) getIncludes().peek();
		}
		else {
			path = TaglibController.getFileBuffer(this).getLocation();
		}

		return path;
	}

	protected DirectiveStructuredDocumentRegionHandler getDirectiveStructuredDocumentRegionHandler() {
		if (fDirectiveHandler == null)
			fDirectiveHandler = new DirectiveStructuredDocumentRegionHandler();
		return fDirectiveHandler;
	}

	/**
	 * Gets the documents.
	 * 
	 * @return Returns a java.util.Hashtable
	 */
	public Hashtable getDocuments() {
		if (fDocuments == null)
			fDocuments = new Hashtable();
		return fDocuments;
	}

	/**
	 * Gets the includes.
	 * 
	 * @return Returns a Stack
	 */
	protected Stack getIncludes() {
		if (fIncludes == null)
			fIncludes = new Stack();
		return fIncludes;
	}

	JSPSourceParser getParser() {
		return fParser;
	}

	public JSPSourceParser getSourceParser() {
		return fParser;
	}

	public StructuredDocumentRegionHandler getStructuredDocumentRegionHandler() {
		return getDirectiveStructuredDocumentRegionHandler();
	}

	/**
	 * 
	 * @return java.util.List
	 */
	public List getTaglibTrackers() {
		if (fTaglibTrackers == null)
			fTaglibTrackers = new ArrayList();
		return fTaglibTrackers;
	}

	void handlePreludes() {
		IStructuredDocumentRegion anchor = new ZeroStructuredDocumentRegion(null, -1);
		fProcessIncludes = false;

		IPath currentPath = getCurrentParserPath();
		if (currentPath != null) {
			PropertyGroup[] propertyGroups = DeploymentDescriptorPropertyCache.getInstance().getPropertyGroups(currentPath);
			for(int k = 0; k < propertyGroups.length; k++) {
				IPath[] preludes = propertyGroups[k].getIncludePrelude();
				for (int i = 0; i < preludes.length; i++) {
					if (!getIncludes().contains(preludes[i]) && !preludes[i].equals(currentPath)) {
						getIncludes().push(preludes[i]);
						if (getParser() != null) {
							IncludeHelper includeHelper = new IncludeHelper(anchor, getParser());
							includeHelper.parse(preludes[i]);
							List references = includeHelper.taglibReferences;
							fTLDCMReferencesMap.put(preludes[i], references);
							for (int j = 0; j < references.size(); j++) {
								TLDCMDocumentReference reference = (TLDCMDocumentReference) references.get(j);
								getParser().addNestablePrefix(new TagMarker(reference.prefix + ":")); //$NON-NLS-1$
							}
						}
						else
							Logger.log(Logger.WARNING, "Warning: parser text was requested by " + getClass().getName() + " but none was available; taglib support disabled"); //$NON-NLS-1$ //$NON-NLS-2$
						getIncludes().pop();
					}
				}
			}
		}

		fProcessIncludes = true;
	}

	/**
	 * @param filePath
	 *            the path to check for modification
	 */
	boolean hasAnyIncludeBeenModified(IPath filePath) {
		boolean result = false;
		// check the top level
		if (hasBeenModified(filePath)) {
			result = true;
		}
		else {
			// check all includees
			Iterator iter = fInclude2TimestampMap.keySet().iterator();
			while (iter.hasNext()) {
				if (hasBeenModified((IPath) iter.next())) {
					result = true;
					break;
				}
			}
		}
		return result;
	}

	/**
	 * @param filename
	 * @return
	 */
	boolean hasBeenModified(IPath filePath) {
		boolean result = false;
		// quick filename/timestamp cache check here...
		IFile f = null;
		if (f == null && filePath.segmentCount() > 1) {
			f = ResourcesPlugin.getWorkspace().getRoot().getFile(filePath);
		}
		if (f != null && f.exists()) {
			Long currentStamp = new Long(f.getModificationStamp());
			Object o = fInclude2TimestampMap.get(filePath);
			if (o != null) {
				Long previousStamp = (Long) o;
				// stamps don't match, file changed
				if (currentStamp.longValue() != previousStamp.longValue()) {
					result = true;
					// store for next time
					fInclude2TimestampMap.put(filePath, currentStamp);
				}
			}
			else {
				// return true, since we've not encountered this file yet.
				result = true;
				// store for next time
				fInclude2TimestampMap.put(filePath, currentStamp);
			}
		}
		return result;
	}

	public void indexChanged(ITaglibIndexDelta event) {
		synchronized (getSharedDocumentCache()) {
			Iterator values = getSharedDocumentCache().values().iterator();
			while (values.hasNext()) {
				Object o = values.next();
				if (o instanceof Reference) {
					values.remove();
				}
			}
		}
	}

	/**
	 * Loads the taglib from the specified URI. It must point to a valid
	 * taglib descriptor to work.
	 */
	protected TLDCMDocumentDescriptor loadTaglib(String uri) {
		TLDCMDocumentDescriptor entry = null;
		IPath currentPath = getCurrentParserPath();
		if (currentPath != null) {
			CMDocument document = null;
			ITaglibRecord record = TaglibIndex.resolve(currentPath.toString(), uri, false);
			if (record != null) {
				document = getCMDocumentBuilder().createCMDocument(record);
				if (document != null) {
					entry = new TLDCMDocumentDescriptor();
					entry.document = document;
					entry.cacheKey = getUniqueIdentifier(record);
				}
			}
			else {
				/* Not a very-often used code path (we hope) */
				IPath currentBaseLocation = getCurrentBaseLocation();
				if (currentBaseLocation != null) {
					String location = URIResolverPlugin.createResolver().resolve(currentBaseLocation.toString(), null, uri);
					if (location != null) {
						if (_debug) {
							System.out.println("Loading tags from " + uri + " at " + location); //$NON-NLS-2$//$NON-NLS-1$
						}
						document = getCMDocumentBuilder().createCMDocument(location);
						entry = new TLDCMDocumentDescriptor();
						entry.document = document;
						entry.cacheKey = location;
					}
				}
			}
		}
		return entry;
	}

	protected void resetTaglibTrackers() {
		if (_debug) {
			System.out.println("TLDCMDocumentManager cleared its taglib trackers\n"); //$NON-NLS-1$
		}
		preludesHandled = false;
		getTaglibTrackers().clear();
	}

	public void setSourceParser(JSPSourceParser parser) {
		if (fParser != null)
			fParser.removeStructuredDocumentRegionHandler(getStructuredDocumentRegionHandler());
		fParser = parser;
		if (fParser != null)
			fParser.addStructuredDocumentRegionHandler(getStructuredDocumentRegionHandler());
	}
}

Back to the top