Uploaded image for project: 'Spatial Information Systems'
  1. Spatial Information Systems
  2. SIS-387

Automatically resolve links in metadata document

    XMLWordPrintableJSON

Details

    • Task
    • Status: Resolved
    • Minor
    • Resolution: Fixed
    • 0.7, 0.8, 1.0, 1.1, 1.2, 1.3, 1.4
    • 1.5
    • Metadata
    • None

    Description

      The ReferenceResolver class allows user to specify what Apache SIS should do when its unmarshal an element defined only by a link to an on-line document. Current implementation does nothing. As a side effect of SIS-345 work, an implementation resolving all links were provided by Image Matters. The code has been extracted in this task for allowing to handle SIS-345 (upgrade to ISO 19115-3) and this task separately.

      package org.apache.sis.xml;
      
      import java.io.IOException;
      import java.net.HttpURLConnection;
      import java.net.MalformedURLException;
      import java.net.URL;
      
      import javax.xml.bind.JAXBException;
      import javax.xml.bind.Unmarshaller;
      
      import org.apache.sis.util.Version;
      import org.apache.sis.xml.MarshalContext;
      import org.apache.sis.xml.MarshallerPool;
      import org.apache.sis.xml.ReferenceResolver;
      import org.apache.sis.xml.XLink;
      import org.apache.sis.xml.XML;
      
      /**
       * This class is used to resolve external references in ISO metadata when unmarshalling.
       * It will <em>always</em> attempt to resolve external references, and will return null
       * if it fails to do so.
       *
       * @author Cullen Rombach (Image Matters)
       */
      public class AllReferenceResolver extends ReferenceResolver {
      
          private Version metadataVersion;
      
          private MarshallerPool pool;
      
          /**
           * Constructor.
           *
           * @param metadataVersion the version of metadata to unmarshal (e.g. ISO 19139)
           */
          public AllReferenceResolver(Version metadataVersion) throws JAXBException {
              super();
              this.metadataVersion = metadataVersion;
          }
      
          @Override
          public <T> T resolve(MarshalContext context, Class<T> type, XLink link) {
              T content = super.resolve(context, type, link);
      
              try {
                  if (content == null) {
                      // Cast the URI in the XLink to a URL.
                      URL href = link.getHRef().toURL();
      
                      // Used for storing a redirect URL if necessary.
                      URL newHref = href;
      
                      // Flag to see if a redirect is necessary.
                      Boolean redirect = true;
      
                      while (redirect) {
                          // Only check for redirects on HTTP and HTTPS connections.
                          if (newHref.getProtocol().contains("http")) {
                              // Open a connection to the URL to check for a redirect if it uses HTTP protocol.
                              HttpURLConnection connection = (HttpURLConnection) newHref.openConnection();
      
                              // Check HTTP status for a possible redirect.
                              int status = connection.getResponseCode();
      
                              // If we need to redirect, do so.
                              if (status == HttpURLConnection.HTTP_MOVED_TEMP
                                      || status == HttpURLConnection.HTTP_MOVED_PERM
                                      || status == HttpURLConnection.HTTP_SEE_OTHER) {
      
                                  // If we need to redirect, get the new URL.
                                  newHref = new URL(connection.getHeaderField("Location"));
                              } // Otherwise, flag that no redirect is necessary.
                              else {
                                  redirect = false;
                              }
                          } // If the link doesn't use HTTP protocol, don't check for a redirect.
                          else {
                              redirect = false;
                          }
                      }
      
                      // Build an Unmarshaller (and the MarshallerPool it belongs to).
                      Unmarshaller unmarshaller = acquireUnmarshaller(metadataVersion);
      
                      // If there was a redirect, unmarshal the new URL.
                      if (!newHref.equals(href)) {
                          content = type.cast(unmarshaller.unmarshal(newHref));
                          pool.recycle(unmarshaller);
                      } // Otherwise, unmarshal the original URL.
                      else if (href != null) {
                          content = type.cast(unmarshaller.unmarshal(href));
                          pool.recycle(unmarshaller);
                      }
                  }
      
                  // If any sort of exception occurred, just return whatever the parent class found.
              } catch (MalformedURLException e) {
                  return content;
              } catch (JAXBException e) {
                  return content;
              } catch (IOException e) {
                  return content;
              }
      
              return content;
          }
      
          /**
           * Get an unmarshaller with its own AllReferenceResolver that operates on the given metadata version.
           *
           * @return a new Unmarshaller.
           */
          private Unmarshaller acquireUnmarshaller(Version metadataVersion) throws JAXBException {
              pool = new MarshallerPool(null);
              Unmarshaller unmarshaller = pool.acquireUnmarshaller();
              // Set metadata version for unmarshalling.
              unmarshaller.setProperty(XML.METADATA_VERSION, metadataVersion);
              // Set resolver for external references.
              unmarshaller.setProperty(XML.RESOLVER, new AllReferenceResolver(metadataVersion));
              return unmarshaller;
          }
      }
      

      Attachments

        Issue Links

          Activity

            People

              desruisseaux Martin Desruisseaux
              desruisseaux Martin Desruisseaux
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: