content: /*
   * 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.aries.blueprint.container;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.Reader;
  import java.net.URI;
  import java.net.URL;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import javax.xml.XMLConstants;
  import javax.xml.transform.Source;
  import javax.xml.transform.stream.StreamSource;
  import javax.xml.validation.Schema;
  import javax.xml.validation.SchemaFactory;
  
  import org.apache.aries.blueprint.NamespaceHandler;
  import org.apache.aries.blueprint.ext.impl.ExtNamespaceHandler;
  import org.apache.aries.blueprint.parser.NamespaceHandlerSet;
  import org.w3c.dom.ls.LSInput;
  import org.w3c.dom.ls.LSResourceResolver;
  import org.xml.sax.SAXException;
  
  public class SimpleNamespaceHandlerSet implements NamespaceHandlerSet {
  
      private Map<URI, URL> namespaces;
      private Map<URI, NamespaceHandler> handlers;
      private Schema schema;
  
      public SimpleNamespaceHandlerSet() {
          this.namespaces = new LinkedHashMap<URI, URL>();
          this.handlers = new LinkedHashMap<URI, NamespaceHandler>();
          ExtNamespaceHandler ext = new ExtNamespaceHandler();
          for (String uri : ExtNamespaceHandler.EXT_URIS) {
              addNamespace(URI.create(uri), ext.getSchemaLocation(uri), ext);
          }
      }
  
      public Set<URI> getNamespaces() {
          return Collections.unmodifiableSet(namespaces.keySet());
      }
  
      public void addNamespace(URI namespace, URL schema, NamespaceHandler handler) {
          namespaces.put(namespace, schema);
          handlers.put(namespace, handler);
      }
  
      public boolean isComplete() {
          return true;
      }
  
      public NamespaceHandler getNamespaceHandler(URI uri) {
          return handlers.get(uri);
      }
  
      @Override
      public Schema getSchema(Map<String, String> locations) throws SAXException, IOException {
          return getSchema();
      }
  
      public Schema getSchema() throws SAXException, IOException {
          if (schema == null) {
              final List<StreamSource> schemaSources = new ArrayList<StreamSource>();
              final List<InputStream> streams = new ArrayList<InputStream>();
              try {
                  InputStream is = getClass().getResourceAsStream("/org/osgi/service/blueprint/blueprint.xsd");
                  streams.add(is);
                  schemaSources.add(new StreamSource(is));
                  for (URI uri : namespaces.keySet()) {
                      is = namespaces.get(uri).openStream();
                      streams.add(is);
                      schemaSources.add(new StreamSource(is));
                  }
                  SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                  schemaFactory.setResourceResolver(new LSResourceResolver() {
                      
                      public LSInput resolveResource(String type, String namespace, String publicId,
                                                     String systemId, String baseURI) {
                          try {
                              URL namespaceURL = namespaces.get(URI.create(namespace));
                              if (systemId != null && namespaceURL != null) {
                                  URI systemIdUri = namespaceURL.toURI();
                                  if (!URI.create(systemId).isAbsolute()) {
                                      systemIdUri = systemIdUri.resolve(systemId);
                                  }
                                  if (!systemIdUri.isAbsolute() && "jar".equals(namespaceURL.getProtocol())) {
                                      String urlString = namespaceURL.toString();
                                      int jarFragmentIndex = urlString.lastIndexOf('!');
                                      if (jarFragmentIndex > 0 && jarFragmentIndex < urlString.length() - 1) {
                                          String jarUrlOnly = urlString.substring(0, jarFragmentIndex);
                                          String oldFragment = urlString.substring(jarFragmentIndex + 1);
                                          String newFragment = URI.create(oldFragment).resolve(systemId).toString();
                                          String newJarUri = jarUrlOnly + '!' + newFragment;
                                          systemIdUri = URI.create(newJarUri);
                                      }
                                  }
                                  InputStream resourceStream = systemIdUri.toURL().openStream();
                                  return new LSInputImpl(publicId, systemId, resourceStream);
                              }
                          } catch (Exception ex) {
                              // ignore
                          }
                          return null;
                      }
                  });
                  schema = schemaFactory.newSchema(schemaSources.toArray(new Source[schemaSources.size()]));
              } finally {
                  for (InputStream is : streams) {
                      is.close();
                  }
              }
          }
          return schema;
      }
  
      public void addListener(Listener listener) {
          throw new IllegalStateException();
      }
  
      public void removeListener(Listener listener) {
          throw new IllegalStateException();
      }
  
      public void destroy() {
          schema = null;
      }
  
      private static class LSInputImpl implements LSInput {
  
          protected String fPublicId;
  
          protected String fSystemId;
  
          protected String fBaseSystemId;
  
          protected InputStream fByteStream;
  
          protected Reader fCharStream;
  
          protected String fData;
  
          protected String fEncoding;
  
          protected boolean fCertifiedText;
  
          LSInputImpl(String publicId, String systemId, InputStream byteStream) {
              fPublicId = publicId;
              fSystemId = systemId;
              fByteStream = byteStream;
          }
  
          public InputStream getByteStream() {
              return fByteStream;
          }
  
          public void setByteStream(InputStream byteStream) {
              fByteStream = byteStream;
          }
  
          public Reader getCharacterStream() {
              return fCharStream;
          }
  
          public void setCharacterStream(Reader characterStream) {
              fCharStream = characterStream;
          }
  
          public String getStringData() {
              return fData;
          }
  
          public void setStringData(String stringData) {
              fData = stringData;
          }
  
          public String getEncoding() {
              return fEncoding;
          }
  
          public void setEncoding(String encoding) {
              fEncoding = encoding;
          }
  
          public String getPublicId() {
              return fPublicId;
          }
  
          public void setPublicId(String publicId) {
              fPublicId = publicId;
          }
  
          public String getSystemId() {
              return fSystemId;
          }
  
          public void setSystemId(String systemId) {
              fSystemId = systemId;
          }
  
          public String getBaseURI() {
              return fBaseSystemId;
          }
  
          public void setBaseURI(String baseURI) {
              fBaseSystemId = baseURI;
          }
  
          public boolean getCertifiedText() {
              return fCertifiedText;
          }
  
          public void setCertifiedText(boolean certifiedText) {
              fCertifiedText = certifiedText;
          }
  
      }
  }
  