| /******************************************************************************* |
| * Copyright (c) 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.contenttype; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.lang.ref.Reference; |
| import java.lang.ref.SoftReference; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceChangeEvent; |
| import org.eclipse.core.resources.IResourceChangeListener; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.IResourceDeltaVisitor; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.jst.jsp.core.internal.Logger; |
| import org.eclipse.jst.jsp.core.internal.util.CommonXML; |
| import org.eclipse.jst.jsp.core.internal.util.FacetModuleCoreSupport; |
| import org.eclipse.jst.jsp.core.internal.util.FileContentCache; |
| import org.eclipse.wst.sse.core.StructuredModelManager; |
| import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.EntityReference; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.EntityResolver; |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| |
| /** |
| * A cache fo property group information stored in web.xml files. Information |
| * is not persisted. |
| */ |
| public final class DeploymentDescriptorPropertyCache { |
| private static final PropertyGroup[] NO_PROPERTY_GROUPS = new PropertyGroup[0]; |
| |
| private static class DeploymentDescriptor { |
| PropertyGroup[] groups; |
| long modificationStamp; |
| Float version = new Float(defaultWebAppVersion); |
| } |
| |
| /** |
| * Representation of the JSP 2.0 property-group definitions from a servlet |
| * deployment descriptor. |
| */ |
| public static final class PropertyGroup { |
| static PropertyGroup createFrom(IPath path, Node propertyGroupNode, int groupNumber) { |
| PropertyGroup group = new PropertyGroup(path, groupNumber); |
| Node propertyGroupID = propertyGroupNode.getAttributes().getNamedItem(ID); |
| if (propertyGroupID != null) { |
| group.setId(propertyGroupID.getNodeValue()); |
| } |
| Node node = propertyGroupNode.getFirstChild(); |
| while (node != null) { |
| if (node.getNodeType() == Node.ELEMENT_NODE) { |
| String name = node.getLocalName(); |
| if (name == null) { |
| name = node.getNodeName(); |
| } |
| if (IS_XML.equals(name)) { |
| group.setIsXML(getContainedText(node)); |
| } |
| else if (EL_IGNORED.equals(name)) { |
| group.setElignored(getContainedText(node)); |
| } |
| else if (INCLUDE_CODA.equals(name)) { |
| group.addCoda(getContainedText(node)); |
| } |
| else if (INCLUDE_PRELUDE.equals(name)) { |
| group.addPrelude(getContainedText(node)); |
| } |
| else if (SCRIPTING_INVALID.equals(name)) { |
| group.setScriptingInvalid(getContainedText(node)); |
| } |
| else if (PAGE_ENCODING.equals(name)) { |
| group.setPageEncoding(getContainedText(node)); |
| } |
| else if (URL_PATTERN.equals(name)) { |
| group.setUrlPattern(getContainedText(node)); |
| } |
| } |
| |
| node = node.getNextSibling(); |
| } |
| |
| return group; |
| } |
| |
| private boolean el_ignored; |
| |
| private String id; |
| |
| private IPath[] include_coda = new IPath[0]; |
| |
| private IPath[] include_prelude = new IPath[0]; |
| private boolean is_xml; |
| private StringMatcher matcher; |
| private String page_encoding; |
| private boolean scripting_invalid; |
| String url_pattern; |
| private IPath webxmlPath; |
| |
| int number; |
| |
| private PropertyGroup(IPath path, int number) { |
| super(); |
| this.webxmlPath = path; |
| this.number = number; |
| } |
| |
| private void addCoda(String containedText) { |
| if (containedText.length() > 0) { |
| IPath[] codas = new IPath[include_coda.length + 1]; |
| System.arraycopy(include_coda, 0, codas, 0, include_coda.length); |
| codas[include_coda.length] = webxmlPath.removeLastSegments(2).append(containedText); |
| include_coda = codas; |
| } |
| } |
| |
| private void addPrelude(String containedText) { |
| if (containedText.length() > 0) { |
| IPath[] preludes = new IPath[include_prelude.length + 1]; |
| System.arraycopy(include_prelude, 0, preludes, 0, include_prelude.length); |
| preludes[include_prelude.length] = webxmlPath.removeLastSegments(2).append(containedText); |
| include_prelude = preludes; |
| } |
| } |
| |
| public String getId() { |
| return id; |
| } |
| |
| public IPath[] getIncludeCoda() { |
| return include_coda; |
| } |
| |
| public IPath[] getIncludePrelude() { |
| return include_prelude; |
| } |
| |
| public String getPageEncoding() { |
| return page_encoding; |
| } |
| |
| public String getUrlPattern() { |
| return url_pattern; |
| } |
| |
| public boolean isELignored() { |
| return el_ignored; |
| } |
| |
| public boolean isIsXML() { |
| return is_xml; |
| } |
| |
| public boolean isScriptingInvalid() { |
| return scripting_invalid; |
| } |
| |
| boolean matches(String pattern, boolean optimistic) { |
| if (matcher == null) |
| return optimistic; |
| return matcher.match(pattern); |
| } |
| |
| private void setElignored(String el_ignored) { |
| this.el_ignored = Boolean.valueOf(el_ignored).booleanValue(); |
| } |
| |
| private void setId(String id) { |
| this.id = id; |
| } |
| |
| private void setIsXML(String is_xml) { |
| this.is_xml = Boolean.valueOf(is_xml).booleanValue(); |
| } |
| |
| private void setPageEncoding(String page_encoding) { |
| this.page_encoding = page_encoding; |
| } |
| |
| private void setScriptingInvalid(String scripting_invalid) { |
| this.scripting_invalid = Boolean.valueOf(scripting_invalid).booleanValue(); |
| } |
| |
| private void setUrlPattern(String url_pattern) { |
| this.url_pattern = url_pattern; |
| if (url_pattern != null && url_pattern.length() > 0) { |
| this.matcher = new StringMatcher(url_pattern); |
| } |
| } |
| |
| public String toString() { |
| return number + ":" + url_pattern; |
| } |
| } |
| |
| private static class ResourceChangeListener implements IResourceChangeListener { |
| public void resourceChanged(IResourceChangeEvent event) { |
| IResourceDelta delta = event.getDelta(); |
| if (event.getType() != IResourceChangeEvent.POST_CHANGE) |
| return; |
| if (delta.getKind() == IResourceDelta.CHANGED && (delta.getFlags() == IResourceDelta.ENCODING || delta.getFlags() == IResourceDelta.MARKERS)) |
| return; |
| IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() { |
| public boolean visit(IResourceDelta delta) { |
| IResource resource = delta.getResource(); |
| if (resource.getType() == IResource.FILE) { |
| IPath path = resource.getFullPath(); |
| int segmentCount = path.segmentCount(); |
| if (segmentCount > 1 && path.lastSegment().equals(WEB_XML) && path.segment(segmentCount - 2).equals(WEB_INF)) { |
| getInstance().deploymentDescriptorChanged(path); |
| } |
| } |
| else if (resource.getType() == IResource.PROJECT) { |
| String name = resource.getName(); |
| if(_debugResolutionCache) { |
| System.out.println("Removing DeploymentDescriptorPropertyCache resolution cache for project " + name); //$NON-NLS-1$ |
| } |
| getInstance().resolvedMap.remove(name); |
| } |
| return true; |
| } |
| }; |
| try { |
| delta.accept(visitor); |
| } |
| catch (CoreException e) { |
| Logger.logException(e); |
| } |
| } |
| } |
| |
| private static class ResourceErrorHandler implements ErrorHandler { |
| private boolean fDoLogExceptions = false; |
| private IPath fPath; |
| |
| ResourceErrorHandler(boolean logExceptions) { |
| super(); |
| fDoLogExceptions = logExceptions; |
| } |
| |
| public void error(SAXParseException exception) throws SAXException { |
| if (fDoLogExceptions) |
| Logger.log(Logger.WARNING, "SAXParseException with " + fPath + " (error) while reading descriptor: " + exception.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| public void fatalError(SAXParseException exception) throws SAXException { |
| if (fDoLogExceptions) |
| Logger.log(Logger.WARNING, "SAXParseException with " + fPath + " (fatalError) while reading descriptor: " + exception.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| public void setPath(IPath path) { |
| fPath = path; |
| } |
| |
| public void warning(SAXParseException exception) throws SAXException { |
| if (fDoLogExceptions) |
| Logger.log(Logger.WARNING, "SAXParseException with " + fPath + " (warning) while reading descriptor: " + exception.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| } |
| |
| /** |
| * Copied from org.eclipse.core.internal.propertytester.StringMatcher, but |
| * should be replaced with a more accurate implementation of the rules in |
| * Servlet spec SRV.11.2 |
| */ |
| private static class StringMatcher { |
| private static final char SINGLE_WILD_CARD = '\u0000'; |
| |
| /** |
| * Boundary value beyond which we don't need to search in the text |
| */ |
| private int bound = 0; |
| |
| private boolean hasLeadingStar; |
| |
| private boolean hasTrailingStar; |
| |
| private final String pattern; |
| |
| private final int patternLength; |
| |
| /** |
| * The pattern split into segments separated by * |
| */ |
| private String segments[]; |
| |
| /** |
| * StringMatcher constructor takes in a String object that is a simple |
| * pattern which may contain '*' for 0 and many characters and '?' for |
| * exactly one character. |
| * |
| * Literal '*' and '?' characters must be escaped in the pattern e.g., |
| * "\*" means literal "*", etc. |
| * |
| * Escaping any other character (including the escape character |
| * itself), just results in that character in the pattern. e.g., "\a" |
| * means "a" and "\\" means "\" |
| * |
| * If invoking the StringMatcher with string literals in Java, don't |
| * forget escape characters are represented by "\\". |
| * |
| * @param pattern |
| * the pattern to match text against |
| */ |
| StringMatcher(String pattern) { |
| if (pattern == null) |
| throw new IllegalArgumentException(); |
| this.pattern = pattern; |
| patternLength = pattern.length(); |
| parseWildCards(); |
| } |
| |
| /** |
| * @param text |
| * a simple regular expression that may only contain '?'(s) |
| * @param start |
| * the starting index in the text for search, inclusive |
| * @param end |
| * the stopping point of search, exclusive |
| * @param p |
| * a simple regular expression that may contain '?' |
| * @return the starting index in the text of the pattern , or -1 if |
| * not found |
| */ |
| private int findPosition(String text, int start, int end, String p) { |
| boolean hasWildCard = p.indexOf(SINGLE_WILD_CARD) >= 0; |
| int plen = p.length(); |
| for (int i = start, max = end - plen; i <= max; ++i) { |
| if (hasWildCard) { |
| if (regExpRegionMatches(text, i, p, 0, plen)) |
| return i; |
| } |
| else { |
| if (text.regionMatches(true, i, p, 0, plen)) |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Given the starting (inclusive) and the ending (exclusive) positions |
| * in the <code>text</code>, determine if the given substring |
| * matches with aPattern |
| * |
| * @return true if the specified portion of the text matches the |
| * pattern |
| * @param text |
| * a String object that contains the substring to match |
| */ |
| public boolean match(String text) { |
| if (text == null) |
| return false; |
| final int end = text.length(); |
| final int segmentCount = segments.length; |
| if (segmentCount == 0 && (hasLeadingStar || hasTrailingStar)) // pattern |
| // contains |
| // only |
| // '*'(s) |
| return true; |
| if (end == 0) |
| return patternLength == 0; |
| if (patternLength == 0) |
| return false; |
| int currentTextPosition = 0; |
| if ((end - bound) < 0) |
| return false; |
| int segmentIndex = 0; |
| String current = segments[segmentIndex]; |
| |
| /* process first segment */ |
| if (!hasLeadingStar) { |
| int currentLength = current.length(); |
| if (!regExpRegionMatches(text, 0, current, 0, currentLength)) |
| return false; |
| segmentIndex++; |
| currentTextPosition = currentTextPosition + currentLength; |
| } |
| if ((segmentCount == 1) && (!hasLeadingStar) && (!hasTrailingStar)) { |
| // only one segment to match, no wild cards specified |
| return currentTextPosition == end; |
| } |
| /* process middle segments */ |
| while (segmentIndex < segmentCount) { |
| current = segments[segmentIndex]; |
| int currentMatch = findPosition(text, currentTextPosition, end, current); |
| if (currentMatch < 0) |
| return false; |
| currentTextPosition = currentMatch + current.length(); |
| segmentIndex++; |
| } |
| |
| /* process final segment */ |
| if (!hasTrailingStar && currentTextPosition != end) { |
| int currentLength = current.length(); |
| return regExpRegionMatches(text, end - currentLength, current, 0, currentLength); |
| } |
| return segmentIndex == segmentCount; |
| } |
| |
| /** |
| * Parses the pattern into segments separated by wildcard '*' |
| * characters. |
| */ |
| private void parseWildCards() { |
| if (pattern.startsWith("*"))//$NON-NLS-1$ |
| hasLeadingStar = true; |
| if (pattern.endsWith("*")) {//$NON-NLS-1$ |
| /* make sure it's not an escaped wildcard */ |
| if (patternLength > 1 && pattern.charAt(patternLength - 2) != '\\') { |
| hasTrailingStar = true; |
| } |
| } |
| |
| ArrayList temp = new ArrayList(); |
| |
| int pos = 0; |
| StringBuffer buf = new StringBuffer(); |
| while (pos < patternLength) { |
| char c = pattern.charAt(pos++); |
| switch (c) { |
| case '\\' : |
| if (pos >= patternLength) { |
| buf.append(c); |
| } |
| else { |
| char next = pattern.charAt(pos++); |
| /* if it's an escape sequence */ |
| if (next == '*' || next == '?' || next == '\\') { |
| buf.append(next); |
| } |
| else { |
| /* |
| * not an escape sequence, just insert |
| * literally |
| */ |
| buf.append(c); |
| buf.append(next); |
| } |
| } |
| break; |
| case '*' : |
| if (buf.length() > 0) { |
| /* new segment */ |
| temp.add(buf.toString()); |
| bound += buf.length(); |
| buf.setLength(0); |
| } |
| break; |
| case '?' : |
| /* |
| * append special character representing single match |
| * wildcard |
| */ |
| buf.append(SINGLE_WILD_CARD); |
| break; |
| default : |
| buf.append(c); |
| } |
| } |
| |
| /* add last buffer to segment list */ |
| if (buf.length() > 0) { |
| temp.add(buf.toString()); |
| bound += buf.length(); |
| } |
| segments = (String[]) temp.toArray(new String[temp.size()]); |
| } |
| |
| /** |
| * |
| * @return boolean |
| * @param text |
| * a String to match |
| * @param tStart |
| * the starting index of match, inclusive |
| * @param p |
| * a simple regular expression that may contain '?' |
| * @param pStart |
| * The start position in the pattern |
| * @param plen |
| * The length of the pattern |
| */ |
| private boolean regExpRegionMatches(String text, int tStart, String p, int pStart, int plen) { |
| while (plen-- > 0) { |
| char tchar = text.charAt(tStart++); |
| char pchar = p.charAt(pStart++); |
| |
| // process wild cards, skipping single wild cards |
| if (pchar == SINGLE_WILD_CARD) |
| continue; |
| if (pchar == tchar) |
| continue; |
| if (Character.toUpperCase(tchar) == Character.toUpperCase(pchar)) |
| continue; |
| // comparing after converting to upper case doesn't handle all |
| // cases; |
| // also compare after converting to lower case |
| if (Character.toLowerCase(tchar) == Character.toLowerCase(pchar)) |
| continue; |
| return false; |
| } |
| return true; |
| } |
| } |
| |
| private static DeploymentDescriptorPropertyCache _instance = new DeploymentDescriptorPropertyCache(); |
| private static final boolean _debugResolutionCache = false; |
| |
| private static final float defaultWebAppVersion = 2.4f; |
| private static String EL_IGNORED = "el-ignored"; |
| private static String ID = "id"; |
| private static String INCLUDE_CODA = "include-coda"; |
| private static String INCLUDE_PRELUDE = "include-prelude"; |
| |
| private static String IS_XML = "is-xml"; |
| private static String JSP_PROPERTY_GROUP = "jsp-property-group"; |
| private static String PAGE_ENCODING = "page-encoding"; |
| |
| private static String SCRIPTING_INVALID = "scripting-invalid"; |
| private static String URL_PATTERN = "url-pattern"; |
| private static final String WEB_APP_ELEMENT_LOCAL_NAME = ":web-app"; |
| private static final String WEB_APP_ELEMENT_NAME = "web-app"; |
| |
| private static final String WEB_APP_VERSION_NAME = "version"; |
| private static final String WEB_INF = "WEB-INF"; |
| private static final String WEB_XML = "web.xml"; |
| // private static final String WEB_INF_WEB_XML = WEB_INF + IPath.SEPARATOR |
| // + WEB_XML; |
| private static final String SLASH_WEB_INF_WEB_XML = Path.ROOT.toString() + WEB_INF + IPath.SEPARATOR + WEB_XML; |
| |
| static String getContainedText(Node parent) { |
| NodeList children = parent.getChildNodes(); |
| if (children.getLength() == 1) { |
| return children.item(0).getNodeValue().trim(); |
| } |
| StringBuffer s = new StringBuffer(); |
| Node child = parent.getFirstChild(); |
| while (child != null) { |
| if (child.getNodeType() == Node.ENTITY_REFERENCE_NODE) { |
| String reference = ((EntityReference) child).getNodeValue(); |
| if (reference == null && child.getNodeName() != null) { |
| reference = "&" + child.getNodeName() + ";"; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| if (reference != null) { |
| s.append(reference.trim()); |
| } |
| } |
| else { |
| s.append(child.getNodeValue().trim()); |
| } |
| child = child.getNextSibling(); |
| } |
| return s.toString().trim(); |
| } |
| |
| public static DeploymentDescriptorPropertyCache getInstance() { |
| return _instance; |
| } |
| |
| /** |
| * This method is not meant to be called by clients. |
| */ |
| public static void start() { |
| ResourcesPlugin.getWorkspace().addResourceChangeListener(getInstance().fResourceChangeListener, IResourceChangeEvent.POST_CHANGE); |
| } |
| |
| /** |
| * This method is not meant to be called by clients. |
| */ |
| public static void stop() { |
| ResourcesPlugin.getWorkspace().removeResourceChangeListener(getInstance().fResourceChangeListener); |
| } |
| |
| private ResourceErrorHandler errorHandler; |
| |
| private Map fDeploymentDescriptors = new Hashtable(); |
| |
| private IResourceChangeListener fResourceChangeListener = new ResourceChangeListener(); |
| |
| // for use when reading TLDs |
| private EntityResolver resolver; |
| |
| Map resolvedMap = new HashMap(); |
| |
| private DeploymentDescriptorPropertyCache() { |
| super(); |
| } |
| |
| private void _parseDocument(IPath path, Float[] version, List groupList, SubProgressMonitor subMonitor, Document document) { |
| Element webapp = document.getDocumentElement(); |
| if (webapp != null) { |
| if (webapp.getTagName().equals(WEB_APP_ELEMENT_NAME) || webapp.getNodeName().endsWith(WEB_APP_ELEMENT_LOCAL_NAME)) { |
| String versionValue = webapp.getAttribute(WEB_APP_VERSION_NAME); |
| if (versionValue != null) { |
| try { |
| version[0] = Float.valueOf(versionValue); |
| } |
| catch (NumberFormatException e) { |
| // doesn't matter |
| } |
| } |
| } |
| } |
| NodeList propertyGroupElements = document.getElementsByTagName(JSP_PROPERTY_GROUP); |
| int length = propertyGroupElements.getLength(); |
| subMonitor.beginTask("Reading Property Groups", length); |
| for (int i = 0; i < length; i++) { |
| PropertyGroup group = PropertyGroup.createFrom(path, propertyGroupElements.item(i), i); |
| subMonitor.worked(1); |
| if (group != null) { |
| groupList.add(group); |
| } |
| } |
| } |
| |
| /** |
| * Convert the SRV spec version to the JSP spec version |
| */ |
| private float convertSpecVersions(float version) { |
| if (version > 0) { |
| if (version == 2.5f) |
| return 2.1f; |
| else if (version == 2.4f) |
| return 2.0f; |
| else if (version == 2.3f) |
| return 1.2f; |
| else if (version == 2.2f) |
| return 1.1f; |
| else if (version == 2.1f) |
| return 1.0f; |
| } |
| return convertSpecVersions(defaultWebAppVersion); |
| } |
| |
| void deploymentDescriptorChanged(final IPath fullPath) { |
| if (fDeploymentDescriptors.containsKey(fullPath.makeAbsolute())) { |
| updateCacheEntry(fullPath); |
| } |
| } |
| |
| /** |
| * parse the specified resource using Xerces, and if that fails, use the |
| * SSE XML parser to find the property groups. |
| */ |
| private DeploymentDescriptor fetchDescriptor(IPath path, IProgressMonitor monitor) { |
| monitor.beginTask("Reading Deployment Descriptor", 3); |
| IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); |
| |
| PropertyGroup groups[] = null; |
| |
| IStructuredModel model = null; |
| List groupList = new ArrayList(); |
| Float[] version = new Float[1]; |
| SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 2); |
| DocumentBuilder builder = CommonXML.getDocumentBuilder(false); |
| builder.setEntityResolver(getEntityResolver()); |
| builder.setErrorHandler(getErrorHandler(path)); |
| try { |
| InputSource inputSource = new InputSource(); |
| String s = FileContentCache.getInstance().getContents(path); |
| inputSource.setCharacterStream(new StringReader(s)); |
| inputSource.setSystemId(path.toString()); |
| Document document = builder.parse(inputSource); |
| _parseDocument(path, version, groupList, subMonitor, document); |
| } |
| catch (SAXException e1) { |
| /* encountered a fatal parsing error, try our own parser */ |
| try { |
| /** |
| * Chiefly because the web.xml file itself is editable, use |
| * SSE to get the DOM Document because it is more fault |
| * tolerant. |
| */ |
| model = StructuredModelManager.getModelManager().getModelForRead(file); |
| monitor.worked(1); |
| if (model instanceof IDOMModel) { |
| IDOMDocument document = ((IDOMModel) model).getDocument(); |
| _parseDocument(path, version, groupList, subMonitor, document); |
| } |
| } |
| catch (Exception e) { |
| Logger.logException(e); |
| } |
| finally { |
| if (model != null) { |
| model.releaseFromRead(); |
| } |
| } |
| } |
| catch (IOException e1) { |
| /* file is unreadable, create no property groups */ |
| } |
| finally { |
| groups = (PropertyGroup[]) groupList.toArray(new PropertyGroup[groupList.size()]); |
| subMonitor.done(); |
| } |
| |
| if (groups == null) { |
| groups = NO_PROPERTY_GROUPS; |
| } |
| |
| DeploymentDescriptor deploymentDescriptor = new DeploymentDescriptor(); |
| deploymentDescriptor.modificationStamp = file.getModificationStamp(); |
| deploymentDescriptor.groups = groups; |
| deploymentDescriptor.version = version[0]; |
| monitor.done(); |
| fDeploymentDescriptors.put(path, new SoftReference(deploymentDescriptor)); |
| return deploymentDescriptor; |
| } |
| |
| private EntityResolver getEntityResolver() { |
| if (resolver == null) { |
| resolver = new EntityResolver() { |
| public InputSource resolveEntity(String publicID, String systemID) throws SAXException, IOException { |
| InputSource result = new InputSource(new ByteArrayInputStream(new byte[0])); |
| result.setPublicId(publicID); |
| result.setSystemId(systemID != null ? systemID : "/_" + getClass().getName()); //$NON-NLS-1$ |
| return result; |
| } |
| }; |
| } |
| return resolver; |
| } |
| |
| /** |
| * Returns an ErrorHandler that will not stop the parser on reported |
| * errors |
| */ |
| private ErrorHandler getErrorHandler(IPath path) { |
| if (errorHandler == null) { |
| errorHandler = new ResourceErrorHandler(false); |
| } |
| errorHandler.setPath(path); |
| return errorHandler; |
| } |
| |
| /** |
| * @param fullPath |
| * @return the JSP version supported by the web application containing the |
| * path. A value stated within a web.xml file takes priority. |
| */ |
| public float getJSPVersion(IPath fullPath) { |
| float version = defaultWebAppVersion; |
| /* try applicable web.xml file first */ |
| IPath webxmlPath = getWebXMLPath(fullPath); |
| if (webxmlPath != null) { |
| IFile webxmlFile = ResourcesPlugin.getWorkspace().getRoot().getFile(webxmlPath); |
| if (webxmlFile.isAccessible()) { |
| Reference descriptorHolder = (Reference) fDeploymentDescriptors.get(webxmlPath); |
| DeploymentDescriptor descriptor = null; |
| |
| if (descriptorHolder == null || ((descriptor = (DeploymentDescriptor) descriptorHolder.get()) == null) || (descriptor.modificationStamp == IResource.NULL_STAMP) || (descriptor.modificationStamp != webxmlFile.getModificationStamp())) { |
| descriptor = fetchDescriptor(webxmlPath, new NullProgressMonitor()); |
| } |
| |
| if (descriptor.version != null) { |
| version = descriptor.version.floatValue(); |
| return convertSpecVersions(version); |
| } |
| } |
| } |
| |
| /* check facet settings */ |
| IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(fullPath.segment(0)); |
| version = FacetModuleCoreSupport.getDynamicWebProjectVersion(project); |
| |
| return convertSpecVersions(version); |
| } |
| |
| /** |
| * @param jspFilePath |
| * @return PropertyGroups matching the file at the given path or an empty |
| * array if no web.xml file exists or no matching property group |
| * was defined. A returned PropertyGroup object should be |
| * considered short-lived and not saved for later use. |
| */ |
| public PropertyGroup[] getPropertyGroups(IPath jspFilePath) { |
| List matchingGroups = new ArrayList(1); |
| IPath webxmlPath = getWebXMLPath(jspFilePath); |
| if (webxmlPath == null) |
| return NO_PROPERTY_GROUPS; |
| |
| IFile webxmlFile = ResourcesPlugin.getWorkspace().getRoot().getFile(webxmlPath); |
| if (!webxmlFile.isAccessible()) |
| return NO_PROPERTY_GROUPS; |
| |
| Reference descriptorHolder = (Reference) fDeploymentDescriptors.get(webxmlPath); |
| DeploymentDescriptor descriptor = null; |
| |
| if (descriptorHolder == null || ((descriptor = (DeploymentDescriptor) descriptorHolder.get()) == null) || (descriptor.modificationStamp == IResource.NULL_STAMP) || (descriptor.modificationStamp != webxmlFile.getModificationStamp())) { |
| descriptor = fetchDescriptor(webxmlPath, new NullProgressMonitor()); |
| } |
| |
| for (int i = 0; i < descriptor.groups.length; i++) { |
| if (descriptor.groups[i].matches(FacetModuleCoreSupport.getRuntimePath(jspFilePath).toString(), false)) { |
| matchingGroups.add(descriptor.groups[i]); |
| } |
| } |
| if (matchingGroups.isEmpty()) { |
| for (int i = 0; i < descriptor.groups.length; i++) { |
| if (descriptor.groups[i].matches(FacetModuleCoreSupport.getRuntimePath(jspFilePath).toString(), true)) { |
| matchingGroups.add(descriptor.groups[i]); |
| } |
| } |
| } |
| return (PropertyGroup[]) matchingGroups.toArray(new PropertyGroup[matchingGroups.size()]); |
| } |
| |
| private IPath getWebXMLPath(IPath fullPath) { |
| /* |
| * It can take the better part of a full second to do this, so cache |
| * the result. |
| */ |
| IPath resolved = null; |
| Map mapForProject = null; |
| mapForProject = (Map) resolvedMap.get(fullPath.segment(0)); |
| if (mapForProject != null) { |
| resolved = (IPath) mapForProject.get(fullPath); |
| } |
| else { |
| mapForProject = new HashMap(); |
| resolvedMap.put(fullPath.segment(0), mapForProject); |
| } |
| |
| if (resolved != null) { |
| if (_debugResolutionCache) { |
| System.out.println("DeploymentDescriptorPropertyCache resolution cache hit for " + fullPath); //$NON-NLS-1$ |
| } |
| } |
| else { |
| if (_debugResolutionCache) { |
| System.out.println("DeploymentDescriptorPropertyCache resolution cache miss for " + fullPath); //$NON-NLS-1$ |
| } |
| resolved = FacetModuleCoreSupport.resolve(fullPath, SLASH_WEB_INF_WEB_XML); |
| mapForProject.put(fullPath, resolved); |
| } |
| return resolved; |
| } |
| |
| private void updateCacheEntry(IPath fullPath) { |
| /* don't update right now; remove and wait for another query to update */ |
| fDeploymentDescriptors.remove(fullPath); |
| } |
| } |