/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.isis.applib.services.jaxb;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* An implementation of {@link SchemaOutputResolver} that keeps track of all the schemas for which it has
* {@link #createOutput(String, String) created} an output {@link StreamResult} containing the content of the schema.
*/
class CatalogingSchemaOutputResolver extends SchemaOutputResolver {
private static final String SCHEMA_LOCATION_INCORRECT = "http://isis.apache.org/schema/common";
private static final String SCHEMA_LOCATION_CORRECT = "http://isis.apache.org/schema/common/common.xsd";
private final JaxbService.IsisSchemas isisSchemas;
private final List<String> namespaceUris = Lists.newArrayList();
public CatalogingSchemaOutputResolver(final JaxbService.IsisSchemas isisSchemas) {
this.isisSchemas = isisSchemas;
}
public List<String> getNamespaceUris() {
return namespaceUris;
}
private Map<String, StreamResultWithWriter> schemaResultByNamespaceUri = Maps.newLinkedHashMap();
public String getSchemaTextFor(final String namespaceUri) {
final StreamResultWithWriter streamResult = schemaResultByNamespaceUri.get(namespaceUri);
if (streamResult == null) {
return null;
}
String xsd = streamResult.asString();
try {
final DocumentBuilderFactory docBuildFactory = DocumentBuilderFactory.newInstance();
final DocumentBuilder parser = docBuildFactory.newDocumentBuilder();
final Document document = parser.parse(new InputSource(new StringReader(xsd)));
final Element el = document.getDocumentElement();
replaceCommonSchemaLocationIfAny(el);
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
final StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(document), new StreamResult(writer));
xsd = writer.toString();
} catch(Exception ex) {
// ignore
}
return xsd;
}
// replace <xs:import namespace="..." schemaLocation="http://isis.apache.org/schema/common"/>
// with <xs:import namespace="..." schemaLocation="http://isis.apache.org/schema/common/common.xsd"/>
private static void replaceCommonSchemaLocationIfAny(final Node node) {
if(schemaLocationReplacedIn(node)) {
return;
}
final NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
final Node currentNode = nodeList.item(i);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
replaceCommonSchemaLocationIfAny(currentNode);
}
}
}
private static boolean schemaLocationReplacedIn(final Node node) {
if(node instanceof Element) {
final Element importEl = (Element) node;
final Attr schemaLocationAttr = importEl.getAttributeNode("schemaLocation");
if(schemaLocationAttr != null) {
final String value = schemaLocationAttr.getValue();
if(SCHEMA_LOCATION_INCORRECT.endsWith(value)) {
schemaLocationAttr.setValue(SCHEMA_LOCATION_CORRECT);
return true;
}
}
}
return false;
}
@Override
public Result createOutput(
final String namespaceUri, final String suggestedFileName) throws IOException {
final StreamResultWithWriter result = new StreamResultWithWriter();
result.setSystemId(namespaceUri);
if (isisSchemas.shouldIgnore(namespaceUri)) {
// skip
} else {
namespaceUris.add(namespaceUri);
schemaResultByNamespaceUri.put(namespaceUri, result);
}
return result;
}
public Map<String, String> asMap() {
final Map<String,String> map = Maps.newLinkedHashMap();
final List<String> namespaceUris = getNamespaceUris();
for (String namespaceUri : namespaceUris) {
map.put(namespaceUri, getSchemaTextFor(namespaceUri));
}
return Collections.unmodifiableMap(map);
}
}