IDEA-64075 Automatic XML Schema discovery

This commit is contained in:
Dmitry Avdeev
2012-07-13 12:15:45 +04:00
parent cd4590630f
commit 1506a615d2
17 changed files with 1817 additions and 59 deletions
@@ -16,31 +16,31 @@
package com.intellij.xml.index;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.xml.NanoXmlUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* @author Dmitry Avdeev
*/
public class XsdNamespaceBuilder extends NanoXmlUtil.IXMLBuilderAdapter {
public class XsdNamespaceBuilder extends NanoXmlUtil.IXMLBuilderAdapter implements Comparable<XsdNamespaceBuilder> {
@Nullable
public static String computeNamespace(final InputStream is) {
return computeNamespace(new InputStreamReader(is));
return computeNamespace(new InputStreamReader(is)).getNamespace();
}
@Nullable
public static String computeNamespace(final Reader reader) {
public static XsdNamespaceBuilder computeNamespace(final Reader reader) {
try {
final XsdNamespaceBuilder builder = new XsdNamespaceBuilder();
NanoXmlUtil.parse(reader, builder);
return builder.myNamespace;
return builder;
}
finally {
try {
@@ -54,25 +54,82 @@ public class XsdNamespaceBuilder extends NanoXmlUtil.IXMLBuilderAdapter {
}
}
private String myCurrentTag;
private int myCurrentDepth;
private String myNamespace;
private String myVersion;
private List<String> myTags = new ArrayList<String>();
private List<String> myAttributes = new ArrayList<String>();
public void startElement(@NonNls final String name, @NonNls final String nsPrefix, @NonNls final String nsURI, final String systemID, final int lineNr)
throws Exception {
if ( !"http://www.w3.org/2001/XMLSchema".equals(nsURI) || !name.equals("schema")) {
stop();
if (myCurrentDepth < 2 && "http://www.w3.org/2001/XMLSchema".equals(nsURI)) {
myCurrentTag = name;
}
myCurrentDepth++;
}
@Override
public void endElement(String name, String nsPrefix, String nsURI) throws Exception {
myCurrentDepth--;
myCurrentTag = null;
}
public void addAttribute(@NonNls final String key, final String nsPrefix, final String nsURI, final String value, final String type)
throws Exception {
if (key.equals("targetNamespace")) {
myNamespace = value;
stop();
if ("schema".equals(myCurrentTag)) {
if ("targetNamespace".equals(key)) {
myNamespace = value;
}
else if ("version".equals(key)) {
myVersion = value;
}
}
else if ("element".equals(myCurrentTag) && "name".equals(key)) {
myTags.add(value);
}
}
public void endElement(final String name, final String nsPrefix, final String nsURI) throws Exception {
stop();
@Override
public int compareTo(XsdNamespaceBuilder o) {
return Comparing.compare(myNamespace, o.myNamespace);
}
public int getRating(String tagName, String version) {
int rate = 0;
if (tagName != null && myTags.contains(tagName)) {
rate |= 0x02;
}
if (Comparing.equal(version, myVersion)) {
rate |= 0x01;
}
return rate;
}
private XsdNamespaceBuilder() {
}
public XsdNamespaceBuilder(String namespace, String version, List<String> tags) {
myNamespace = namespace;
myVersion = version;
myTags = tags;
}
public String getNamespace() {
return myNamespace;
}
public String getVersion() {
return myVersion;
}
public List<String> getTags() {
return myTags;
}
public List<String> getAttributes() {
return myAttributes;
}
}
@@ -372,6 +372,10 @@
<category>XML</category>
<className>com.intellij.codeInsight.daemon.impl.analysis.AddSchemaPrefixIntention</className>
</intentionAction>
<intentionAction>
<category>XML</category>
<className>com.intellij.codeInsight.daemon.impl.quickfix.AddXsiSchemaLocationForExtResourceAction</className>
</intentionAction>
<intentionAction>
<category>XML</category>
<className>com.intellij.codeInsight.daemon.impl.analysis.ConvertSchemaPrefixToDefaultIntention</className>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<<spot>xs</spot>:schema targetNamespace="http://mySchema"
xmlns:<spot>xs</spot>="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://mySchema">
<<spot>xs</spot>:element name="myElement" type="my:TYPE"/>
<<spot>xs</spot>:simpleType name="TYPE" id="TYPE">
<<spot>xs</spot>:restriction base="<spot>xs</spot>:integer">
<<spot>xs</spot>:minInclusive value="0" id="nonNegativeInteger.minInclusive"/>
</<spot>xs</spot>:restriction>
</<spot>xs</spot>:simpleType>
</<spot>xs</spot>:schema>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://mySchema"
<spot>xmlns</spot>="http://www.w3.org/2001/XMLSchema"
xmlns:my="http://mySchema">
<element name="myElement" type="my:TYPE"/>
<simpleType name="TYPE" id="TYPE">
<restriction base="integer">
<minInclusive value="0" id="nonNegativeInteger.minInclusive"/>
</restriction>
</simpleType>
</schema>
@@ -0,0 +1,5 @@
<html>
<body>
Adds xsi:schemaLocation attribute.
</body>
</html>
@@ -19,15 +19,20 @@ import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.daemon.XmlErrorMessages;
import com.intellij.codeInsight.daemon.impl.analysis.CreateNSDeclarationIntentionFix;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.XmlElementFactory;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.xml.XmlBundle;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -91,4 +96,17 @@ public class AddXsiSchemaLocationForExtResourceAction extends BaseExtResourceAct
final TextRange textRange = new TextRange(range.getEndOffset() - offset - 1, range.getEndOffset() - 1);
editor.getCaretModel().moveToOffset(textRange.getStartOffset());
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (!(file instanceof XmlFile)) return false;
PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
XmlAttributeValue value = PsiTreeUtil.getParentOfType(element, XmlAttributeValue.class);
if (value == null) return false;
XmlAttribute attribute = PsiTreeUtil.getParentOfType(value, XmlAttribute.class);
if (attribute == null || !"xmlns".equals(attribute.getLocalName())) return false;
setText(XmlBundle.message(getQuickFixKeyId()));
return true;
}
}
@@ -79,11 +79,8 @@ abstract class BaseExtResourceAction extends BaseIntentionAction {
public static String findUri(PsiFile file, int offset) {
PsiReference currentRef = file.getViewProvider().findReferenceAt(offset, file.getLanguage());
if (currentRef == null) currentRef = file.getViewProvider().findReferenceAt(offset);
if (( currentRef instanceof URLReference ||
currentRef instanceof URIReferenceProvider.DependentNSReference
) &&
currentRef.resolve() == null
) {
if (currentRef instanceof URLReference ||
currentRef instanceof URIReferenceProvider.DependentNSReference) {
return currentRef.getCanonicalText();
}
return null;
@@ -23,6 +23,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.*;
@@ -58,6 +59,9 @@ import com.intellij.xml.XmlExtension;
import com.intellij.xml.XmlNSDescriptor;
import com.intellij.xml.impl.dtd.XmlNSDescriptorImpl;
import com.intellij.xml.impl.schema.AnyXmlElementDescriptor;
import com.intellij.xml.index.IndexedRelevantResource;
import com.intellij.xml.index.XmlNamespaceIndex;
import com.intellij.xml.index.XsdNamespaceBuilder;
import com.intellij.xml.util.XmlTagUtil;
import com.intellij.xml.util.XmlUtil;
import gnu.trove.THashMap;
@@ -335,7 +339,7 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
return new Result<XmlNSDescriptor>(descriptor, ArrayUtil.append(descriptor.getDependences(), XmlTagImpl.this));
}
XmlFile currentFile = retrieveFile(fileLocation, version);
XmlFile currentFile = retrieveFile(fileLocation, version, namespace);
if (currentFile == null) {
final XmlDocument document = XmlUtil.getContainingFile(XmlTagImpl.this).getDocument();
if (document != null) {
@@ -392,16 +396,21 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
}
@Nullable
private XmlFile retrieveFile(final String fileLocation, String version) {
private XmlFile retrieveFile(final String fileLocation, final String version, String namespace) {
final String targetNs = XmlUtil.getTargetSchemaNsFromTag(this);
if (fileLocation.equals(targetNs)) {
return null;
}
else {
final XmlFile file = XmlUtil.getContainingFile(this);
final PsiFile psiFile = ExternalResourceManager.getInstance().getResourceLocation(fileLocation, file, version);
return psiFile instanceof XmlFile ? (XmlFile)psiFile : null;
final XmlFile file = XmlUtil.getContainingFile(this);
final PsiFile psiFile = ExternalResourceManager.getInstance().getResourceLocation(fileLocation, file, version);
if (psiFile instanceof XmlFile) {
return (XmlFile)psiFile;
}
IndexedRelevantResource<String,XsdNamespaceBuilder> resource =
XmlNamespaceIndex.guessSchema(namespace, myLocalName, version, ModuleUtilCore.findModuleForPsiElement(file));
return resource == null ? null : (XmlFile)file.getManager().findFile(resource.getFile());
}
@Nullable
@@ -28,64 +28,120 @@ import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.*;
/**
* @author Dmitry Avdeev
*/
public class XmlNamespaceIndex extends XmlIndex<String> {
public class XmlNamespaceIndex extends XmlIndex<XsdNamespaceBuilder> {
@Nullable
public static String getNamespace(@NotNull VirtualFile file, final Project project) {
final List<String> list = FileBasedIndex.getInstance().getValues(NAME, file.getUrl(), createFilter(project));
return list.size() == 0 ? null : list.get(0);
final List<XsdNamespaceBuilder> list = FileBasedIndex.getInstance().getValues(NAME, file.getUrl(), createFilter(project));
return list.size() == 0 ? null : list.get(0).getNamespace();
}
public static List<IndexedRelevantResource<String, String>> getResourcesByNamespace(String namespace, final Project project, Module module) {
List<IndexedRelevantResource<String, String>> resources = IndexedRelevantResource.getResources(NAME, namespace, module, project,
public static List<IndexedRelevantResource<String, XsdNamespaceBuilder>> getResourcesByNamespace(String namespace, final Project project, Module module) {
List<IndexedRelevantResource<String, XsdNamespaceBuilder>> resources = IndexedRelevantResource.getResources(NAME, namespace, module, project,
null);
Collections.sort(resources);
return resources;
}
public static List<IndexedRelevantResource<String, String>> getAllResources(@NotNull final Module module) {
public static List<IndexedRelevantResource<String, XsdNamespaceBuilder>> getAllResources(@NotNull final Module module) {
return getAllResources(module, null);
}
public static List<IndexedRelevantResource<String, String>> getAllResources(@NotNull final Module module, @Nullable NullableFunction<List<IndexedRelevantResource<String, String>>, IndexedRelevantResource<String, String>> chooser) {
public static List<IndexedRelevantResource<String, XsdNamespaceBuilder>> getAllResources(@NotNull final Module module,
@Nullable NullableFunction<List<IndexedRelevantResource<String, XsdNamespaceBuilder>>, IndexedRelevantResource<String, XsdNamespaceBuilder>> chooser) {
return IndexedRelevantResource.getAllResources(NAME, module, chooser);
}
private static final ID<String,String> NAME = ID.create("XmlNamespaces");
private static final ID<String,XsdNamespaceBuilder> NAME = ID.create("XmlNamespaces");
@Override
@NotNull
public ID<String, String> getName() {
public ID<String, XsdNamespaceBuilder> getName() {
return NAME;
}
@Override
@NotNull
public DataIndexer<String, String, FileContent> getIndexer() {
return new DataIndexer<String, String, FileContent>() {
public DataIndexer<String, XsdNamespaceBuilder, FileContent> getIndexer() {
return new DataIndexer<String, XsdNamespaceBuilder, FileContent>() {
@Override
@NotNull
public Map<String, String> map(final FileContent inputData) {
final String ns = XsdNamespaceBuilder.computeNamespace(CharArrayUtil.readerFromCharSequence(inputData.getContentAsText()));
final HashMap<String, String> map = new HashMap<String, String>(2);
if (ns != null) {
map.put(ns, "");
public Map<String, XsdNamespaceBuilder> map(final FileContent inputData) {
final XsdNamespaceBuilder
builder = XsdNamespaceBuilder.computeNamespace(CharArrayUtil.readerFromCharSequence(inputData.getContentAsText()));
final HashMap<String, XsdNamespaceBuilder> map = new HashMap<String, XsdNamespaceBuilder>(2);
String namespace = builder.getNamespace();
if (namespace != null) {
map.put(namespace, builder);
}
map.put(inputData.getFile().getUrl(), ns == null ? "" : ns);
map.put(inputData.getFile().getUrl(), builder);
return map;
}
};
}
@Override
public DataExternalizer<String> getValueExternalizer() {
return KEY_DESCRIPTOR;
public DataExternalizer<XsdNamespaceBuilder> getValueExternalizer() {
return new DataExternalizer<XsdNamespaceBuilder>() {
@Override
public void save(DataOutput out, XsdNamespaceBuilder value) throws IOException {
out.writeUTF(value.getNamespace() == null ? "" : value.getNamespace());
out.writeUTF(value.getVersion() == null ? "" : value.getVersion());
out.writeInt(value.getTags().size());
for (String s : value.getTags()) {
out.writeUTF(s);
}
}
@Override
public XsdNamespaceBuilder read(DataInput in) throws IOException {
int count;
XsdNamespaceBuilder builder = new XsdNamespaceBuilder(in.readUTF(), in.readUTF(), new ArrayList<String>(count = in.readInt()));
for (int i = 0; i < count; i++) {
builder.getTags().add(in.readUTF());
}
return builder;
}
};
}
@Override
public int getVersion() {
return 2;
}
@Nullable
public static IndexedRelevantResource<String, XsdNamespaceBuilder> guessSchema(String namespace,
@Nullable final String tagName,
@Nullable final String version,
Module module) {
if (module == null) return null;
Project project = module.getProject();
final List<IndexedRelevantResource<String, XsdNamespaceBuilder>>
resources = getResourcesByNamespace(namespace, project, module);
if (resources.isEmpty()) return null;
return Collections
.max(resources, new Comparator<IndexedRelevantResource<String, XsdNamespaceBuilder>>() {
@Override
public int compare(IndexedRelevantResource<String, XsdNamespaceBuilder> o1,
IndexedRelevantResource<String, XsdNamespaceBuilder> o2) {
int i = o1.getValue().getRating(tagName, version) - o2.getValue().getRating(tagName, version);
return i == 0 ? o1.compareTo(o2) : i;
}
});
}
}
@@ -67,6 +67,7 @@ import com.intellij.xml.impl.schema.XmlElementDescriptorImpl;
import com.intellij.xml.impl.schema.XmlNSDescriptorImpl;
import com.intellij.xml.index.IndexedRelevantResource;
import com.intellij.xml.index.XmlNamespaceIndex;
import com.intellij.xml.index.XsdNamespaceBuilder;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -251,11 +252,12 @@ public class XmlUtil {
}
public static Collection<XmlFile> findNSFilesByURI(String namespace, final Project project, Module module) {
final List<IndexedRelevantResource<String,String>> resources = XmlNamespaceIndex.getResourcesByNamespace(namespace, project, module);
final List<IndexedRelevantResource<String,XsdNamespaceBuilder>>
resources = XmlNamespaceIndex.getResourcesByNamespace(namespace, project, module);
final PsiManager psiManager = PsiManager.getInstance(project);
return ContainerUtil.mapNotNull(resources, new NullableFunction<IndexedRelevantResource<String, String>, XmlFile>() {
public XmlFile fun(IndexedRelevantResource<String, String> stringStringIndexedRelevantResource) {
PsiFile file = psiManager.findFile(stringStringIndexedRelevantResource.getFile());
return ContainerUtil.mapNotNull(resources, new NullableFunction<IndexedRelevantResource<String, XsdNamespaceBuilder>, XmlFile>() {
public XmlFile fun(IndexedRelevantResource<String, XsdNamespaceBuilder> resource) {
PsiFile file = psiManager.findFile(resource.getFile());
return file instanceof XmlFile ? (XmlFile)file : null;
}
});
@@ -8,6 +8,7 @@ import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -44,6 +45,14 @@ public class XmlSchemaIndexTest extends CodeInsightFixtureTestCase {
assertTrue(xstags.contains("schema"));
}
public void testXsdNamespaceBuilder() throws Exception {
VirtualFile file = myFixture.copyFileToProject("web-app_2_5.xsd");
final XsdNamespaceBuilder builder = XsdNamespaceBuilder.computeNamespace(new InputStreamReader(file.getInputStream()));
assertEquals("http://java.sun.com/xml/ns/javaee", builder.getNamespace());
assertEquals("2.5", builder.getVersion());
assertEquals(Arrays.asList("web-app"), builder.getTags());
}
public void testTagNameIndex() {
myFixture.copyDirectoryToProject("", "");
@@ -72,11 +81,26 @@ public class XmlSchemaIndexTest extends CodeInsightFixtureTestCase {
myFixture.copyDirectoryToProject("", "");
final List<IndexedRelevantResource<String, String>> files =
XmlNamespaceIndex.getResourcesByNamespace("http://www.springframework.org/schema/beans",
final List<IndexedRelevantResource<String, XsdNamespaceBuilder>> files =
XmlNamespaceIndex.getResourcesByNamespace("http://java.sun.com/xml/ns/javaee",
getProject(),
myModule);
assertEquals(1, files.size());
assertEquals(2, files.size());
IndexedRelevantResource<String, XsdNamespaceBuilder>
resource = XmlNamespaceIndex.guessSchema("http://java.sun.com/xml/ns/javaee", "web-app", "3.0", myModule);
assertNotNull(resource);
XsdNamespaceBuilder builder = resource.getValue();
assertEquals("http://java.sun.com/xml/ns/javaee", builder.getNamespace());
assertEquals("3.0", builder.getVersion());
assertEquals(Arrays.asList("web-app"), builder.getTags());
resource = XmlNamespaceIndex.guessSchema("http://java.sun.com/xml/ns/javaee", "web-app", "2.5", myModule);
assertNotNull(resource);
builder = resource.getValue();
assertEquals("http://java.sun.com/xml/ns/javaee", builder.getNamespace());
assertEquals("2.5", builder.getVersion());
assertEquals(Arrays.asList("web-app"), builder.getTags());
}
@Override
File diff suppressed because it is too large Load Diff
+272
View File
@@ -0,0 +1,272 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://java.sun.com/xml/ns/javaee"
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
version="3.0">
<xsd:annotation>
<xsd:documentation>
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright 2003-2009 Sun Microsystems, Inc. All rights reserved.
The contents of this file are subject to the terms of either the
GNU General Public License Version 2 only ("GPL") or the Common
Development and Distribution License("CDDL") (collectively, the
"License"). You may not use this file except in compliance with
the License. You can obtain a copy of the License at
https://glassfish.dev.java.net/public/CDDL+GPL.html or
glassfish/bootstrap/legal/LICENSE.txt. See the License for the
specific language governing permissions and limitations under the
License.
When distributing the software, include this License Header
Notice in each file and include the License file at
glassfish/bootstrap/legal/LICENSE.txt. Sun designates this
particular file as subject to the "Classpath" exception as
provided by Sun in the GPL Version 2 section of the License file
that accompanied this code. If applicable, add the following
below the License Header, with the fields enclosed by brackets []
replaced by your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"
Contributor(s):
If you wish your version of this file to be governed by only the
CDDL or only the GPL Version 2, indicate your decision by adding
"[Contributor] elects to include this software in this
distribution under the [CDDL or GPL Version 2] license." If you
don't indicate a single choice of license, a recipient has the
option to distribute your version of this file under either the
CDDL, the GPL Version 2 or to extend the choice of license to its
licensees as provided above. However, if you add GPL Version 2
code and therefore, elected the GPL Version 2 license, then the
option applies only if the new code is made subject to such
option by the copyright holder.
</xsd:documentation>
</xsd:annotation>
<xsd:annotation>
<xsd:documentation>
<![CDATA[[
This is the XML Schema for the Servlet 3.0 deployment descriptor.
The deployment descriptor must be named "WEB-INF/web.xml" in the
web application's war file. All Servlet deployment descriptors
must indicate the web application schema by using the Java EE
namespace:
http://java.sun.com/xml/ns/javaee
and by indicating the version of the schema by
using the version element as shown below:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="..."
version="3.0">
...
</web-app>
The instance documents may indicate the published version of
the schema using the xsi:schemaLocation attribute for Java EE
namespace with the following location:
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:annotation>
<xsd:documentation>
The following conventions apply to all Java EE
deployment descriptor elements unless indicated otherwise.
- In elements that specify a pathname to a file within the
same JAR file, relative filenames (i.e., those not
starting with "/") are considered relative to the root of
the JAR file's namespace. Absolute filenames (i.e., those
starting with "/") also specify names in the root of the
JAR file's namespace. In general, relative names are
preferred. The exception is .war files where absolute
names are preferred for consistency with the Servlet API.
</xsd:documentation>
</xsd:annotation>
<xsd:include schemaLocation="web-common_3_0.xsd"/>
<!-- **************************************************** -->
<xsd:element name="web-app"
type="javaee:web-appType">
<xsd:annotation>
<xsd:documentation>
The web-app element is the root of the deployment
descriptor for a web application. Note that the sub-elements
of this element can be in the arbitrary order. Because of
that, the multiplicity of the elements of distributable,
session-config, welcome-file-list, jsp-config, login-config,
and locale-encoding-mapping-list was changed from "?" to "*"
in this schema. However, the deployment descriptor instance
file must not contain multiple elements of session-config,
jsp-config, and login-config. When there are multiple elements of
welcome-file-list or locale-encoding-mapping-list, the container
must concatenate the element contents. The multiple occurence
of the element distributable is redundant and the container
treats that case exactly in the same way when there is only
one distributable.
</xsd:documentation>
</xsd:annotation>
<xsd:unique name="web-common-servlet-name-uniqueness">
<xsd:annotation>
<xsd:documentation>
The servlet element contains the name of a servlet.
The name must be unique within the web application.
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:servlet"/>
<xsd:field xpath="javaee:servlet-name"/>
</xsd:unique>
<xsd:unique name="web-common-filter-name-uniqueness">
<xsd:annotation>
<xsd:documentation>
The filter element contains the name of a filter.
The name must be unique within the web application.
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:filter"/>
<xsd:field xpath="javaee:filter-name"/>
</xsd:unique>
<xsd:unique name="web-common-ejb-local-ref-name-uniqueness">
<xsd:annotation>
<xsd:documentation>
The ejb-local-ref-name element contains the name of an EJB
reference. The EJB reference is an entry in the web
application's environment and is relative to the
java:comp/env context. The name must be unique within
the web application.
It is recommended that name is prefixed with "ejb/".
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:ejb-local-ref"/>
<xsd:field xpath="javaee:ejb-ref-name"/>
</xsd:unique>
<xsd:unique name="web-common-ejb-ref-name-uniqueness">
<xsd:annotation>
<xsd:documentation>
The ejb-ref-name element contains the name of an EJB
reference. The EJB reference is an entry in the web
application's environment and is relative to the
java:comp/env context. The name must be unique within
the web application.
It is recommended that name is prefixed with "ejb/".
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:ejb-ref"/>
<xsd:field xpath="javaee:ejb-ref-name"/>
</xsd:unique>
<xsd:unique name="web-common-resource-env-ref-uniqueness">
<xsd:annotation>
<xsd:documentation>
The resource-env-ref-name element specifies the name of
a resource environment reference; its value is the
environment entry name used in the web application code.
The name is a JNDI name relative to the java:comp/env
context and must be unique within a web application.
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:resource-env-ref"/>
<xsd:field xpath="javaee:resource-env-ref-name"/>
</xsd:unique>
<xsd:unique name="web-common-message-destination-ref-uniqueness">
<xsd:annotation>
<xsd:documentation>
The message-destination-ref-name element specifies the name of
a message destination reference; its value is the
environment entry name used in the web application code.
The name is a JNDI name relative to the java:comp/env
context and must be unique within a web application.
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:message-destination-ref"/>
<xsd:field xpath="javaee:message-destination-ref-name"/>
</xsd:unique>
<xsd:unique name="web-common-res-ref-name-uniqueness">
<xsd:annotation>
<xsd:documentation>
The res-ref-name element specifies the name of a
resource manager connection factory reference. The name
is a JNDI name relative to the java:comp/env context.
The name must be unique within a web application.
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:resource-ref"/>
<xsd:field xpath="javaee:res-ref-name"/>
</xsd:unique>
<xsd:unique name="web-common-env-entry-name-uniqueness">
<xsd:annotation>
<xsd:documentation>
The env-entry-name element contains the name of a web
application's environment entry. The name is a JNDI
name relative to the java:comp/env context. The name
must be unique within a web application.
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:env-entry"/>
<xsd:field xpath="javaee:env-entry-name"/>
</xsd:unique>
<xsd:key name="web-common-role-name-key">
<xsd:annotation>
<xsd:documentation>
A role-name-key is specified to allow the references
from the security-role-refs.
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:security-role"/>
<xsd:field xpath="javaee:role-name"/>
</xsd:key>
<xsd:keyref name="web-common-role-name-references"
refer="javaee:web-common-role-name-key">
<xsd:annotation>
<xsd:documentation>
The keyref indicates the references from
security-role-ref to a specified role-name.
</xsd:documentation>
</xsd:annotation>
<xsd:selector xpath="javaee:servlet/javaee:security-role-ref"/>
<xsd:field xpath="javaee:role-link"/>
</xsd:keyref>
</xsd:element>
</xsd:schema>
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="<error>http://java.sun.<caret>com/xml/ns/j2ee</error>"/>
<web-app xmlns="http://java.sun.co<caret>m/xml/ns/j2ee" version="2.4"/>
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:q="<error>aaa</error>" xsi:schemaLocation="<error>aaa</error> aaa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="<error>http://java.sun.<caret>com/xml/ns/j2ee</error>"/>
<web-app xmlns:q="<error>aaa</error>" xsi:schemaLocation="<error>aaa</error> aaa" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.<caret>com/xml/ns/j2ee" version="2.4"/>
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:q="aaa" xsi:schemaLocation="aaa aaa
http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee"/>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4"/>
@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" version="2.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"/>