/** * 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); } }