blob: 9f5085899270f91070796b85b6fb1c9d55f67902 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2004 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.j2ee.internal.web.taglib.registry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jem.util.logger.proxy.Logger;
import org.eclipse.jst.j2ee.internal.project.IWebNatureConstants;
import org.eclipse.jst.j2ee.internal.web.locator.WebProjectTaglibLocator;
import org.eclipse.jst.j2ee.internal.web.locator.WebXMLTaglibLocator;
import org.eclipse.jst.j2ee.internal.web.taglib.ITaglibInfo;
import org.eclipse.jst.j2ee.internal.web.taglib.ITaglibLocator;
import org.eclipse.jst.j2ee.internal.web.taglib.ITaglibRegistry;
import org.eclipse.jst.j2ee.internal.web.taglib.ITaglibRegistryListener;
/**
* @version 1.0
* @author
*/
abstract public class AbstractTaglibRegistry implements ITaglibRegistry {
private static final boolean debug = false;
protected IProject project;
protected Vector listeners;
protected Vector taglibs; // of type ITaglibInfo
protected ITaglibLocator[] locators;
protected boolean needsRefresh = false;
public AbstractTaglibRegistry(IProject project) {
this.project = project;
initialize();
refresh();
}
protected void initialize() {
this.locators = new ITaglibLocator[]{new WebProjectTaglibLocator(this.project), new WebXMLTaglibLocator(this.project)};
}
/*
* @see ITaglibRegistry#addTaglibRegistryListener(ITaglibRegistryListener)
*/
protected void addTaglib(ITaglibInfo taglib) {
// Add web.xml entries at the top of the list so that they are
// always returned first from the getTaglib(uri) method.
if (taglib.isWebXMLEntry())
this.taglibs.add(0, taglib);
else
this.taglibs.add(taglib);
}
public void addTaglibRegistryListener(ITaglibRegistryListener listener) {
if (this.listeners == null)
this.listeners = new Vector();
this.listeners.add(listener);
}
/*
* @see ITaglibRegistry#getTaglib(IPath)
*/
public ITaglibInfo[] getTaglibs(IPath location) {
Vector results = getTaglibsVector(location);
return (ITaglibInfo[]) results.toArray(new ITaglibInfo[results.size()]);
}
protected Vector getTaglibsVector(IPath location) {
Vector results = new Vector();
Vector tTaglibs = primGetTaglibs();
boolean isWebXML = isWebXMLFile(location);
// Start at the beginning of the taglib list and return the first
// one that matches the location passed in.
for (Iterator iter = tTaglibs.iterator(); iter.hasNext();) {
ITaglibInfo taglib = (ITaglibInfo) iter.next();
if (isWebXML) {
if (taglib.isWebXMLEntry())
results.add(taglib);
} else if (taglib.getLocation().equals(location))
results.add(taglib);
}
return results;
}
protected Vector getExistingTaglibs(IPath location) {
Vector results = new Vector();
Vector tTaglibs = this.taglibs;
boolean isWebXML = isWebXMLFile(location);
// Start at the beginning of the taglib list and return the first
// one that matches the location passed in.
for (Iterator iter = tTaglibs.iterator(); iter.hasNext();) {
ITaglibInfo taglib = (ITaglibInfo) iter.next();
if (isWebXML) {
if (taglib.isWebXMLEntry())
results.add(taglib);
} else if (taglib.getLocation().equals(location) && !taglib.isWebXMLEntry())
results.add(taglib);
}
return results;
}
public IProject getProject() {
return this.project;
}
/*
* @see ITaglibRegistry#getRecommendedTaglibs()
*/
public ITaglibInfo[] getRecommendedTaglibs() {
// we pass false because we dont want to show all entries per resource,just one
return getValidTaglibs(false);
}
/*
* @see ITaglibRegistry#getVisibleTaglibs()
*/
public ITaglibInfo[] getVisibleTaglibs() {
// we pass true because we want to show all entries that are valid uri's for a resource
return getValidTaglibs(true);
}
protected ITaglibInfo[] getValidTaglibs(boolean showAllEntriesPerResource) {
Vector allTaglibs = primGetTaglibs();
Vector results = new Vector(allTaglibs.size());
Set locationSet = new HashSet();
Set uriSet = new HashSet();
// first pass web.xml entries
for (Iterator iter = allTaglibs.iterator(); iter.hasNext();) {
ITaglibInfo iTaglib = (ITaglibInfo) iter.next();
if (iTaglib.isWebXMLEntry()) {
if (!uriSet.contains(iTaglib.getURI())) {
// show all web.xml entries whether they are mapped to the same resource
// if(showAllEntriesPerResource ||
// !locationSet.contains(iTaglib.getLocation())){
if (!locationSet.contains(iTaglib.getLocation()))
locationSet.add(iTaglib.getLocation());
results.add(iTaglib);
// }
uriSet.add(iTaglib.getURI());
}
}
}
// second pass uri in tld entries
for (Iterator iter = allTaglibs.iterator(); iter.hasNext();) {
ITaglibInfo iTaglib = (ITaglibInfo) iter.next();
if (iTaglib.isURIFromTLD() && !iTaglib.isWebXMLEntry()) {
if (!uriSet.contains(iTaglib.getURI())) {
if (!iTaglib.isInJar()) {
// i.e its a tld file in the web application
if (showAllEntriesPerResource || !locationSet.contains(iTaglib.getLocation())) {
if (!locationSet.contains(iTaglib.getLocation()))
locationSet.add(iTaglib.getLocation());
results.add(iTaglib);
}
} else { // i.e its a tld file in a JAR file in the web application
String jarRelativePath = iTaglib.getTLDLocation().toString();
if (jarRelativePath.equalsIgnoreCase(IWebNatureConstants.META_INFO_DIRECTORY + "/taglib.tld")) { //$NON-NLS-1$
if (!iTaglib.isServerContribution() // dont add META-INF/taglib.tld that
// comes from a server
&& (showAllEntriesPerResource || !locationSet.contains(iTaglib.getLocation()))) {
if (!locationSet.contains(iTaglib.getLocation()))
locationSet.add(iTaglib.getLocation());
results.add(iTaglib);
}
} else { // if not metainf/taglib.tld
// we want to include all the non meta-inf entries in the results
results.add(iTaglib);
}
}
uriSet.add(iTaglib.getURI());
} // if !uriSet.contains
} // if .isURIFromTLD
}
// third pass for entries whose uri's are resource paths
for (Iterator iter = allTaglibs.iterator(); iter.hasNext();) {
ITaglibInfo iTaglib = (ITaglibInfo) iter.next();
if (!iTaglib.isURIFromTLD() && !iTaglib.isWebXMLEntry() && !iTaglib.isDirectoryEntry()) {
if (!uriSet.contains(iTaglib.getURI())) {
if (showAllEntriesPerResource || !locationSet.contains(iTaglib.getLocation())) {
results.add(iTaglib);
locationSet.add(iTaglib.getLocation());
}
}
}
}
// fourth pass for entries whose uri's are resource paths & directory entries
for (Iterator iter = allTaglibs.iterator(); iter.hasNext();) {
ITaglibInfo iTaglib = (ITaglibInfo) iter.next();
if (iTaglib.isDirectoryEntry()) {
IPath directoryLoc = iTaglib.getLocation();
if (!uriSet.contains(iTaglib.getURI())) {
boolean canAdd = true;
for (Iterator iterator = locationSet.iterator(); iterator.hasNext();) {
IPath locationPath = (IPath) iterator.next();
if (directoryLoc.matchingFirstSegments(locationPath) == locationPath.segmentCount() - 1) {
canAdd = false;
break;
}
}
if (canAdd) {// don't add directories that have tld's in them
results.add(iTaglib);
locationSet.add(iTaglib.getLocation());
}
}
}
}
return (ITaglibInfo[]) results.toArray(new ITaglibInfo[results.size()]);
}
protected Vector primGetTaglibs() {
if (this.needsRefresh)
refresh();
return this.taglibs;
}
/*
* @see ITaglibRegistry#getTaglibs()
*/
public ITaglibInfo[] getTaglibs() {
Vector tTaglibs = primGetTaglibs();
return (ITaglibInfo[]) tTaglibs.toArray(new ITaglibInfo[tTaglibs.size()]);
}
/*
* @see ITaglibRegistry#getTaglib(String)
*/
public ITaglibInfo getTaglib(String uri) {
List tTaglibs = Arrays.asList(getVisibleTaglibs());
//commented out because we dont want to return the taglib for resources that are not
// visible
// or are not visible because of precedence //primGetTaglibs();
for (Iterator iter = tTaglibs.iterator(); iter.hasNext();) {
ITaglibInfo taglib = (ITaglibInfo) iter.next();
if (taglib.getURI().equals(uri))
return taglib;
}
return null;
}
protected void fireTaglibAdded(ITaglibInfo addedTaglib) {
if (debug)
System.out.println("TaglibRegistry: taglib added: " + addedTaglib); //$NON-NLS-1$
if (this.listeners == null)
return;
for (Iterator iter = this.listeners.iterator(); iter.hasNext();) {
ITaglibRegistryListener listener = (ITaglibRegistryListener) iter.next();
listener.taglibAdded(addedTaglib);
}
}
protected void fireTaglibChanged(ITaglibInfo changedTaglib) {
if (debug)
System.out.println("TaglibRegistry: taglib changed: " + changedTaglib); //$NON-NLS-1$
if (this.listeners == null)
return;
for (Iterator iter = this.listeners.iterator(); iter.hasNext();) {
ITaglibRegistryListener listener = (ITaglibRegistryListener) iter.next();
listener.taglibChanged(changedTaglib);
}
}
protected void fireTaglibRemoved(ITaglibInfo removedTaglib) {
if (debug)
System.out.println("TaglibRegistry: taglib removed: " + removedTaglib); //$NON-NLS-1$
if (this.listeners == null)
return;
for (Iterator iter = this.listeners.iterator(); iter.hasNext();) {
ITaglibRegistryListener listener = (ITaglibRegistryListener) iter.next();
listener.taglibRemoved(removedTaglib);
}
}
abstract protected boolean isWebXMLFile(IPath filePath);
protected boolean isTaglibTLD(IPath tldPath) {
return tldPath.lastSegment().equalsIgnoreCase("taglib.tld"); //$NON-NLS-1$
}
public void processResourceChanged(IResourceDelta delta) {
int kind = delta.getKind();
IResource resource = delta.getResource();
int flags = delta.getFlags();
if (delta.getKind() == IResourceDelta.CHANGED && flags == IResourceDelta.NO_CHANGE)
return;
// If the websettings file changed, refresh everything in case the context root
// was modified or the J2EE level was changed.
if (requiresFullUpdate(delta)) {
updateAll();
return;
}
// Make sure resource is not null
if (resource == null)
return;
// Only process resource changes that are under the refreshRoot.
IPath resourcePath = resource.getProjectRelativePath();
IResource refreshRoot = getRefreshRoot();
// RATLC00974251 for a java project before build is done, output location does not exist
if (refreshRoot == null)
return;
IPath refreshPath = refreshRoot.getProjectRelativePath();
if (resourcePath.matchingFirstSegments(refreshPath) != refreshPath.segmentCount())
return;
if (debug)
System.out.println("TaglibRegistry(" + this.project.getName() + ").resourceChanged: " + delta); //$NON-NLS-1$ //$NON-NLS-2$
if (kind == IResourceDelta.CHANGED || kind == IResourceDelta.REPLACED) {
handleResourceModified(resource);
} else if (kind == IResourceDelta.REMOVED) {
handleResourceRemoved(resource);
} else if (kind == IResourceDelta.ADDED) {
handleResourceAdded(resource);
} else {
if (debug)
System.out.println("TaglibRegistry.resourceChanged: UNHANDLED DELTA TYPE"); //$NON-NLS-1$
}
}
protected void handleResourceAdded(IResource resource) {
handleResourceModified(resource);
}
protected void handleResourceModified(IResource resource) {
try {
resource.accept(new IResourceVisitor() {
public boolean visit(IResource aresource) throws CoreException {
if (aresource.getType() != IResource.ROOT && AbstractTaglibRegistry.this.project != aresource.getProject())
return false;
if (aresource.getType() == IResource.FILE) {
processFile(aresource);
return false;
}
if (shouldProcessDirectory(aresource)) {
processDirectory(aresource);
}
return (canVisitResource(aresource));
}
});
} catch (CoreException e) {
Logger.getLogger().log(e);
}
}
/**
* Return true if the resource and its children should be visited
*
* @param resource
* @return
*/
protected boolean canVisitResource(IResource resource) {
if (resource.getType() != IResource.ROOT && this.project != resource.getProject())
return false;
if (resource.getType() != IResource.FILE)
return true;
return true;
}
protected void handleResourceRemoved(IResource resource) {
IPath location = resource.getProjectRelativePath();
ITaglibInfo[] removedTaglibs = removeTaglibs(location);
if (removedTaglibs != null) {
for (int i = 0; i < removedTaglibs.length; i++) {
ITaglibInfo iTaglibInfo = removedTaglibs[i];
if (debug)
System.out.println("TaglibRegistry.handleResourceRemoved taglib removed: " + iTaglibInfo); //$NON-NLS-1$
fireTaglibRemoved(iTaglibInfo);
}
}
}
protected IResource getRefreshRoot() {
return getProject();
}
public void refresh() {
this.taglibs = new Vector();
IResource refreshRoot = getRefreshRoot();
// RATLC00974251 for a java project before build is done, output location does not exist
if (refreshRoot != null)
handleResourceAdded(refreshRoot);
this.needsRefresh = false;
}
protected void updateAll() {
try {
IResource refreshRoot = getRefreshRoot();
// RATLC00974251 for a java project before build is done, output location does not exist
if (refreshRoot == null)
return;
refreshRoot.accept(new IResourceVisitor() {
public boolean visit(IResource resource) throws CoreException {
handleResourceModified(resource);
return true;
}
});
} catch (CoreException e) {
//Do nothing
}
}
/**
* Remove all the taglibs associated with the location.
*
* @param location
* @return ITaglibInfo[] The taglibs that are removed. Null if none are removed.
*/
protected ITaglibInfo[] removeTaglibs(IPath location) {
List results = new ArrayList();
boolean isWebXML = isWebXMLFile(location);
for (int i = 0; i < this.taglibs.size(); i++) {
ITaglibInfo taglib = (ITaglibInfo) this.taglibs.get(i);
if (isWebXML) {
if (taglib.isWebXMLEntry()) {
removeTaglib(i);
results.add(taglib);
i--;
}
} else if (taglib.getLocation().equals(location)) {
removeTaglib(i);
results.add(taglib);
i--;
}
}
return results.isEmpty() ? null : (ITaglibInfo[]) results.toArray(new ITaglibInfo[results.size()]);
}
abstract protected boolean requiresFullUpdate(IResourceDelta delta);
protected void removeTaglib(int i) {
this.taglibs.remove(i);
}
protected ITaglibInfo[] searchForTaglibs(IResource resource) {
ArrayList results = new ArrayList();
for (int i = 0; i < this.locators.length; i++) {
ITaglibLocator tLocator = this.locators[i];
ITaglibInfo[] tTaglibs = tLocator.search(resource);
if (tTaglibs != null) {
for (int j = 0; j < tTaglibs.length; j++) {
results.add(tTaglibs[j]);
}
}
}
return (ITaglibInfo[]) results.toArray(new ITaglibInfo[results.size()]);
}
/*
* @see ITaglibRegistry#removeTaglibRegistryListener(ITaglibRegistryListener)
*/
public void removeTaglibRegistryListener(ITaglibRegistryListener listener) {
if (this.listeners == null)
return;
this.listeners.remove(listener);
}
/*
* @see Object#toString()
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("TaglibRegistry: \n"); //$NON-NLS-1$
for (Iterator iter = this.taglibs.iterator(); iter.hasNext();) {
ITaglibInfo taglib = (ITaglibInfo) iter.next();
sb.append("\t"); //$NON-NLS-1$
sb.append(taglib);
sb.append("\n"); //$NON-NLS-1$
}
return sb.toString();
}
protected void processDirectory(IResource resource) {
// do nothing
}
protected boolean shouldProcessDirectory(IResource resource) {
return true;
}
/**
* @param resource
*/
protected void processFile(IResource resource) {
Vector existingTaglibs = getExistingTaglibs(resource.getProjectRelativePath());
ITaglibInfo[] newTaglibs = searchForTaglibs(resource);
for (int i = 0; i < newTaglibs.length; i++) {
ITaglibInfo newTaglib = newTaglibs[i];
int existingIndex = existingTaglibs.indexOf(newTaglib);
if (existingIndex >= 0) {
// If its an exact match, leave it in alone the taglibs registry
// but fire a taglibChangedEvent.
if (!newTaglib.isWebXMLEntry())
fireTaglibChanged(newTaglib);
existingTaglibs.remove(existingIndex);
} else {
// The taglib did not exist previously in the list, add it and
// fire a taglibAdded event.
addTaglib(newTaglib);
fireTaglibAdded(newTaglib);
}
}
for (Iterator iter = existingTaglibs.iterator(); iter.hasNext();) {
ITaglibInfo remainingTaglib = (ITaglibInfo) iter.next();
this.taglibs.remove(remainingTaglib);
fireTaglibRemoved(remainingTaglib);
}
}
}