Skip to content
This repository was archived by the owner on Feb 12, 2022. It is now read-only.

Commit f2e2a63

Browse files
committed
Fix XSD validation for includes with subdirectories in global schemas
1 parent 44d6a38 commit f2e2a63

File tree

11 files changed

+190
-14
lines changed

11 files changed

+190
-14
lines changed

src/main/java/org/raml/model/Raml.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.raml.parser.annotation.Mapping;
2727
import org.raml.parser.annotation.Scalar;
2828
import org.raml.parser.annotation.Sequence;
29+
import org.raml.parser.builder.GlobalSchemaSequenceTupleBuilder;
2930
import org.raml.parser.resolver.ResourceHandler;
3031
import org.raml.parser.rule.SecurityReferenceSequenceRule;
3132

@@ -53,7 +54,7 @@ public class Raml implements Serializable
5354
@Scalar()
5455
private String mediaType;
5556

56-
@Sequence(rule = org.raml.parser.rule.GlobalSchemasRule.class)
57+
@Sequence(rule = org.raml.parser.rule.GlobalSchemasRule.class, builder = GlobalSchemaSequenceTupleBuilder.class)
5758
private List<Map<String, String>> schemas = new ArrayList<Map<String, String>>();
5859

5960
private transient Map<String, Object> compiledSchemas;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2013 (c) MuleSoft, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing,
11+
* software distributed under the License is distributed on an
12+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13+
* either express or implied. See the License for the specific
14+
* language governing permissions and limitations under the License.
15+
*/
16+
package org.raml.parser.builder;
17+
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
21+
public class GlobalSchemaMapTupleBuilder extends MapTupleBuilder
22+
{
23+
24+
public static final Class<String> VALUE_CLASS = String.class;
25+
26+
public GlobalSchemaMapTupleBuilder()
27+
{
28+
super(VALUE_CLASS);
29+
}
30+
31+
protected void addBuilders()
32+
{
33+
TupleBuilder tupleBuilder = new GlobalSchemaScalarTupleBuilder();
34+
Map<String, TupleBuilder<?,?>> builderMap = new HashMap<String, TupleBuilder<?, ?>>();
35+
builderMap.put(null, tupleBuilder);
36+
this.setChildrenTupleBuilders(builderMap);
37+
}
38+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2013 (c) MuleSoft, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing,
11+
* software distributed under the License is distributed on an
12+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13+
* either express or implied. See the License for the specific
14+
* language governing permissions and limitations under the License.
15+
*/
16+
package org.raml.parser.builder;
17+
18+
import org.raml.parser.utils.ReflectionUtils;
19+
import org.raml.parser.visitor.SchemaCompiler;
20+
import org.yaml.snakeyaml.nodes.ScalarNode;
21+
22+
public class GlobalSchemaScalarTupleBuilder extends ScalarTupleBuilder
23+
{
24+
25+
private String key;
26+
27+
public GlobalSchemaScalarTupleBuilder()
28+
{
29+
super(null, String.class);
30+
}
31+
32+
@Override
33+
public Object buildValue(Object parent, ScalarNode node)
34+
{
35+
String value = SchemaCompiler.encodeIncludePath(node);
36+
ReflectionUtils.setProperty(parent, key, value);
37+
return parent;
38+
}
39+
40+
@Override
41+
public void buildKey(Object parent, ScalarNode tuple)
42+
{
43+
super.buildKey(parent, tuple);
44+
this.key = tuple.getValue();
45+
}
46+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2013 (c) MuleSoft, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing,
11+
* software distributed under the License is distributed on an
12+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13+
* either express or implied. See the License for the specific
14+
* language governing permissions and limitations under the License.
15+
*/
16+
package org.raml.parser.builder;
17+
18+
import java.util.HashMap;
19+
20+
public class GlobalSchemaSequenceTupleBuilder extends SequenceTupleBuilder
21+
{
22+
23+
public GlobalSchemaSequenceTupleBuilder()
24+
{
25+
super("schemas", new HashMap<String, String>(){}.getClass().getGenericSuperclass());
26+
}
27+
28+
@Override
29+
public NodeBuilder getItemBuilder()
30+
{
31+
return new GlobalSchemaMapTupleBuilder();
32+
}
33+
}

src/main/java/org/raml/parser/builder/MapTupleBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public MapTupleBuilder(String fieldName, Class<?> valueClass)
4444
this.valueClass = valueClass;
4545
}
4646

47-
private void addBuilders()
47+
protected void addBuilders()
4848
{
4949
TupleBuilder tupleBuilder;
5050
if (ReflectionUtils.isPojo(getValueClass()))

src/main/java/org/raml/parser/visitor/RamlDocumentBuilder.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
import static org.raml.parser.rule.BaseUriRule.URI_PATTERN;
1919

2020
import java.lang.reflect.Field;
21+
import java.util.HashMap;
22+
import java.util.List;
23+
import java.util.Map;
2124
import java.util.Stack;
2225
import java.util.regex.Matcher;
2326
import java.util.regex.Pattern;
@@ -152,7 +155,13 @@ private void compileGlobalSchemas()
152155
{
153156
SchemaCompiler compiler = SchemaCompiler.getInstance();
154157
Raml raml = getDocumentObject();
155-
raml.setCompiledSchemas(compiler.compile(raml.getConsolidatedSchemas()));
158+
Map<String, Object> compiledSchemas = new HashMap<String, Object>();
159+
List<Map<String, String>> schemas = raml.getSchemas();
160+
for (Map<String, String> schemaMap : schemas)
161+
{
162+
compiledSchemas.putAll(compiler.compile(schemaMap));
163+
}
164+
raml.setCompiledSchemas(compiledSchemas);
156165
}
157166

158167
private void populateDefaultUriParameters(Resource resource)

src/main/java/org/raml/parser/visitor/SchemaCompiler.java

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Map;
2121

2222
import javax.xml.XMLConstants;
23+
import javax.xml.bind.DatatypeConverter;
2324
import javax.xml.transform.stream.StreamSource;
2425
import javax.xml.validation.Schema;
2526
import javax.xml.validation.SchemaFactory;
@@ -28,11 +29,14 @@
2829
import org.raml.parser.XsdResourceResolver;
2930
import org.raml.parser.loader.ResourceLoader;
3031
import org.raml.parser.tagresolver.ContextPath;
32+
import org.raml.parser.tagresolver.IncludeResolver;
33+
import org.yaml.snakeyaml.nodes.ScalarNode;
3134

32-
public class SchemaCompiler
35+
public final class SchemaCompiler
3336
{
3437

35-
private final static SchemaCompiler instance = new SchemaCompiler();
38+
private static final String SEPARATOR = "-|_";
39+
private static final SchemaCompiler instance = new SchemaCompiler();
3640
private ContextPath contextPath;
3741
private ResourceLoader resourceLoader;
3842

@@ -55,28 +59,35 @@ public void init(ContextPath contextPath, ResourceLoader resourceLoader)
5559
this.resourceLoader = resourceLoader;
5660
}
5761

58-
public Map<String, Object> compile(Map<String, String> schemas)
62+
public Map<String, Object> compile(Map<String, String> encodedSchemas)
5963
{
6064
Map<String, Object> compiledSchemas = new HashMap<String, Object>();
61-
for (Map.Entry<String, String> schema : schemas.entrySet())
65+
for (Map.Entry<String, String> encodedSchema : encodedSchemas.entrySet())
6266
{
63-
Schema compiledSchema = compile(schema.getValue());
67+
String[] pathAndSchema = decodeIncludePath(encodedSchema.getValue());
68+
Schema compiledSchema = compile(pathAndSchema[1], pathAndSchema[0]);
6469
if (compiledSchema != null)
6570
{
66-
compiledSchemas.put(schema.getKey(), compiledSchema);
71+
compiledSchemas.put(encodedSchema.getKey(), compiledSchema);
6772
}
73+
encodedSchema.setValue(pathAndSchema[1]);
6874
}
6975
return compiledSchemas;
7076
}
7177

72-
public Schema compile(String schema)
78+
public Schema compile(String schema, String path)
7379
{
7480
Schema compiledSchema = null;
7581
String trimmedSchema = StringUtils.trimToEmpty(schema);
7682
if (trimmedSchema.startsWith("<") && trimmedSchema.endsWith(">"))
7783
{
7884
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
79-
factory.setResourceResolver(new XsdResourceResolver(contextPath, resourceLoader));
85+
ContextPath actualContextPath = contextPath;
86+
if (path != null)
87+
{
88+
actualContextPath = new ContextPath(new IncludeInfo(path));
89+
}
90+
factory.setResourceResolver(new XsdResourceResolver(actualContextPath, resourceLoader));
8091
try
8192
{
8293
compiledSchema = factory.newSchema(new StreamSource(new StringReader(trimmedSchema)));
@@ -89,4 +100,35 @@ public Schema compile(String schema)
89100
}
90101
return compiledSchema;
91102
}
103+
104+
public Schema compile(String schema)
105+
{
106+
return compile(schema, null);
107+
}
108+
109+
public static String encodeIncludePath(ScalarNode node)
110+
{
111+
String schema = node.getValue();
112+
String includePath = "";
113+
if (node instanceof IncludeResolver.IncludeScalarNode)
114+
{
115+
includePath = ((IncludeResolver.IncludeScalarNode) node).getIncludeName();
116+
}
117+
String includeEncoded = DatatypeConverter.printBase64Binary(includePath.getBytes());
118+
119+
return includeEncoded + SEPARATOR + schema;
120+
}
121+
122+
public static String[] decodeIncludePath(String encodedSchema)
123+
{
124+
int idx = encodedSchema.indexOf(SEPARATOR);
125+
if (idx == -1)
126+
{
127+
throw new IllegalArgumentException("Invalid include encoded schema.");
128+
}
129+
String base64Path = encodedSchema.substring(0, idx);
130+
String includePath = new String(DatatypeConverter.parseBase64Binary(base64Path));
131+
String schema = encodedSchema.substring(idx + SEPARATOR.length(), encodedSchema.length());
132+
return new String[] {includePath, schema};
133+
}
92134
}

src/test/java/org/raml/parser/builder/SchemaBuilderTestCase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public void xsdWithInclude()
3636
MimeType mimeType = raml.getResources().get("/name").getAction(GET).getResponses().get("200").getBody().get("application/xml");
3737
assertThat(mimeType.getCompiledSchema(), is(Schema.class));
3838
assertThat(mimeType.getSchema(), is(String.class));
39-
assertThat(mimeType.getSchema(), containsString("include schemaLocation=\"refs/xsd-include.xsd\""));
39+
assertThat(mimeType.getSchema(), containsString("include schemaLocation=\"xsd-include.xsd\""));
4040
}
4141

4242
@Test
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<xs:schema targetNamespace="http://www.example.org/simple"
3+
elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"
4+
xmlns="http://www.example.org/simple">
5+
<xs:include schemaLocation="xsd-include.xsd"></xs:include>
6+
<xs:element name="message" type="Message"></xs:element>
7+
</xs:schema>

src/test/resources/org/raml/schema/xsd-global-includer.raml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
---
33
title: Sample API
44
schemas:
5-
- name-schema: !include xsd-includer.xsd
5+
- name-schema: !include refs/xsd-includer-nested.xsd
66
/name:
77
get:
88
responses:

0 commit comments

Comments
 (0)