Package org.fao.geonet.kernel.harvest.harvester.ogcwxs

Source Code of org.fao.geonet.kernel.harvest.harvester.ogcwxs.Harvester

//=============================================================================
//===  Copyright (C) 2001-2007 Food and Agriculture Organization of the
//===  United Nations (FAO-UN), United Nations World Food Programme (WFP)
//===  and United Nations Environment Programme (UNEP)
//===
//===  This program is free software; you can redistribute it and/or modify
//===  it under the terms of the GNU General Public License as published by
//===  the Free Software Foundation; either version 2 of the License, or (at
//===  your option) any later version.
//===
//===  This program is distributed in the hope that it will be useful, but
//===  WITHOUT ANY WARRANTY; without even the implied warranty of
//===  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
//===  General Public License for more details.
//===
//===  You should have received a copy of the GNU General Public License
//===  along with this program; if not, write to the Free Software
//===  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
//===
//===  Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
//===  Rome - Italy. email: geonetwork@osgeo.org
//==============================================================================

package org.fao.geonet.kernel.harvest.harvester.ogcwxs;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import jeeves.server.context.ServiceContext;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.fao.geonet.GeonetContext;
import org.fao.geonet.Logger;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.constants.Params;
import org.fao.geonet.domain.Metadata;
import org.fao.geonet.domain.MetadataType;
import org.fao.geonet.kernel.DataManager;
import org.fao.geonet.kernel.SchemaManager;
import org.fao.geonet.kernel.harvest.BaseAligner;
import org.fao.geonet.kernel.harvest.harvester.AbstractHarvester;
import org.fao.geonet.kernel.harvest.harvester.CategoryMapper;
import org.fao.geonet.kernel.harvest.harvester.GroupMapper;
import org.fao.geonet.kernel.harvest.harvester.HarvestError;
import org.fao.geonet.kernel.harvest.harvester.HarvestResult;
import org.fao.geonet.kernel.harvest.harvester.IHarvester;
import org.fao.geonet.kernel.harvest.harvester.UUIDMapper;
import org.fao.geonet.kernel.setting.SettingManager;
import org.fao.geonet.lib.Lib;
import org.fao.geonet.repository.MetadataRepository;
import org.fao.geonet.repository.Updater;
import org.fao.geonet.services.thumbnail.Set;
import org.fao.geonet.util.FileCopyMgr;
import org.fao.geonet.util.Sha1Encoder;
import org.fao.geonet.utils.BinaryFile;
import org.fao.geonet.utils.GeonetHttpRequestFactory;
import org.fao.geonet.utils.Xml;
import org.fao.geonet.utils.XmlRequest;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.filter.ElementFilter;
import org.jdom.xpath.XPath;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.net.URL;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;


//=============================================================================
/**
* A OgcWxSHarvester is able to generate metadata for data and service
* from a GetCapabilities documents. Metadata for layers are generated
* using layer information contained in the GetCapabilities document
* or using a xml document pointed by the metadataUrl attribute of layer
* element.
*
* OGC services supported are :
* <ul>
*   <li>WMS</li>
*   <li>WFS</li>
*   <li>WCS</li>
*   <li>WPS</li>
*   <li>SOS</li>
* </ul>
*
* Metadata produced are :
* <ul>
*   <li>ISO19119 for service's metadata</li>
*   <li>ISO19139 for data's metadata</li>
* </ul>
*
*  Note : Layer stands for "Layer" for WMS, "FeatureType" for WFS
*  and "Coverage" for WCS.
* <pre> 
* <nodes>
<node type="ogcwxs" id="113">
*    <site>
*      <name>TEST</name>
*      <uuid>c1da2928-c866-49fd-adde-466fe36d3508</uuid>
*      <account>
*        <use>true</use>
*        <username />
*        <password />
*      </account>
*      <url>http://localhost:8080/geoserver/wms</url>
*      <ogctype>WMS111</ogctype>
*      <icon>default.gif</icon>
*    </site>
*    <options>
*      <every>90</every>
*      <oneRunOnly>false</oneRunOnly>
*      <status>active</status>
*      <lang>eng</lang>
*      <useLayer>true</useLayer>
*      <useLayerMd>false</useLayerMd>
*      <datasetCategory></datasetCategory>
*    </options>
*    <privileges>
*      <group id="1">
*        <operation name="view" />
*      </group>
*    </privileges>
*    <categories>
*      <category id="3" />
*    </categories>
*    <info>
*      <lastRun>2007-12-05T16:17:20</lastRun>
*      <running>false</running>
*    </info>
</node>
* </nodes>
* </pre>
*
* @author fxprunayre
*  
*/
class Harvester extends BaseAligner implements IHarvester<HarvestResult>
{
 
 
  /**
     * Constructor
     * 
     * @param log   
     * @param context    Jeeves context
     * @param params  Information about harvesting configuration for the node
     *
     * @return null
     */
  public Harvester(Logger log,
            ServiceContext context,
            OgcWxSParams params) {
    this.log    = log;
    this.context= context;
    this.params = params;

    result = new HarvestResult();
   
    GeonetContext gc = (GeonetContext) context.getHandlerContext (Geonet.CONTEXT_NAME);
    dataMan = gc.getBean(DataManager.class);
    schemaMan = gc.getBean(SchemaManager.class);
    }

  //---------------------------------------------------------------------------
  //---
  //--- API methods
  //---
  //---------------------------------------------------------------------------
  /**
     * Start the harvesting of a WMS, WFS or WCS node.
     */
  public HarvestResult harvest(Logger log) throws Exception {
        Element xml;
       
        this.log = log;

        log.info("Retrieving remote metadata information for : " + params.name);
       
    // Clean all before harvest : Remove/Add mechanism
        // If harvest failed (ie. if node unreachable), metadata will be removed, and
        // the node will not be referenced in the catalogue until next harvesting.
        // TODO : define a rule for UUID in order to be able to do an update operation ?
        UUIDMapper localUuids = new UUIDMapper(context.getBean(MetadataRepository.class), params.uuid);


        // Try to load capabilities document
    this.capabilitiesUrl = getBaseUrl(params.url) +
            "SERVICE=" + params.ogctype.substring(0,3) +
            "&VERSION=" + params.ogctype.substring(3) +
            "&REQUEST=" + GETCAPABILITIES
            ;

        if(log.isDebugEnabled()) {
            log.debug("GetCapabilities document: " + this.capabilitiesUrl);
        }
   
        XmlRequest req = context.getBean(GeonetHttpRequestFactory.class).createXmlRequest();
        req.setUrl(new URL(this.capabilitiesUrl));
        req.setMethod(XmlRequest.Method.GET);
        Lib.net.setupProxy(context, req);

        if (params.useAccount) {
            req.setCredentials(params.username, params.password);
        }

        xml = req.execute();

    //-----------------------------------------------------------------------
    //--- remove old metadata
    for (String uuid : localUuids.getUUIDs())
    {
      String id = localUuids.getID (uuid);

            if(log.isDebugEnabled()) log.debug ("  - Removing old metadata before update with id: " + id);

      // Remove thumbnails
      unsetThumbnail (id);
     
      // Remove metadata
      dataMan.deleteMetadata (context, id);
     
      result.locallyRemoved ++;
    }


        if (result.locallyRemoved > 0) {
            dataMan.flush();
        }
   
        // Convert from GetCapabilities to ISO19119
        addMetadata (xml);
        dataMan.flush();

        result.totalMetadata = result.addedMetadata + result.layer;
   
    return result;
  }
 
 

  /**
     * Add metadata to the node for a WxS service
     * 
   *  1.Use GetCapabilities Document
   *  2.Transform using XSLT to iso19119
   *  3.Loop through layers
   *  4.Create md for layer
   *  5.Add operatesOn elem with uuid
   *  6.Save all
     * 
     * @param capa      GetCapabilities document
     *                  
     */
   private void addMetadata (Element capa) throws Exception
   {
    if (capa == null)
      return;

    //--- Loading categories and groups
    localCateg   = new CategoryMapper (context);
    localGroups = new GroupMapper (context);

    // md5 the full capabilities URL
    String uuid = Sha1Encoder.encodeString (this.capabilitiesUrl); // is the service identifier
   
    //--- Loading stylesheet
    String styleSheet = schemaMan.getSchemaDir(params.outputSchema) +
              Geonet.Path.CONVERT_STYLESHEETS
              + "/OGCWxSGetCapabilitiesto19119/"
              + "/OGC"
              + params.ogctype.substring(0,3)
              + "GetCapabilities-to-ISO19119_ISO19139.xsl";

         if(log.isDebugEnabled()) log.debug ("  - XSLT transformation using " + styleSheet);
   
    Map<String, Object> param = new HashMap<String, Object>();
    param.put("lang", params.lang);
    param.put("topic", params.topic);
    param.put("uuid", uuid);
   
    Element md = Xml.transform (capa, styleSheet, param);
   
    String schema = dataMan.autodetectSchema (md, null); // ie. iso19139;

    if (schema == null) {
      log.warning("Skipping metadata with unknown schema.");
      result.unknownSchema ++;
    }


    //--- Create metadata for layers only if user ask for
    if (params.useLayer || params.useLayerMd) {     
      // Load CRS
      // TODO
     
      //--- Select layers, featureTypes and Coverages (for layers having no child named layer = not take group of layer into account)
      // and add the metadata
      XPath xp = XPath.newInstance ("//Layer[count(./*[name(.)='Layer'])=0] | " +
                      "//wms:Layer[count(./*[name(.)='Layer'])=0] | " +
                      "//wfs:FeatureType | " +
                      "//wcs:CoverageOfferingBrief | " +
                      "//sos:ObservationOffering");
      xp.addNamespace("wfs", "http://www.opengis.net/wfs");
      xp.addNamespace("wcs", "http://www.opengis.net/wcs");
      xp.addNamespace("wms", "http://www.opengis.net/wms");
      xp.addNamespace("sos", "http://www.opengis.net/sos/1.0");
                   
      @SuppressWarnings("unchecked")
            List<Element> layers = xp.selectNodes(capa);
      if (layers.size()>0) {
        log.info("  - Number of layers, featureTypes or Coverages found : " + layers.size());
     
        for (Element layer : layers) {
          WxSLayerRegistry s = addLayerMetadata (layer, capa);
          if (s != null)
            layersRegistry.add(s);
        }      
       
        // Update ISO19119 for data/service links creation (ie. operatesOn element)
        // The editor will support that but it will make quite heavy XML.
        md = addOperatesOnUuid (md, layersRegistry);
      }
    } 

        // Save iso19119 metadata in DB
    log.info("  - Adding metadata for services with " + uuid);
    DateFormat df = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss");
    Date date = new Date();

        //
        // insert metadata
        //
        String group = null, isTemplate = null, docType = null, title = null, category = null;
        boolean ufo = false, indexImmediate = false;
        String id = dataMan.insertMetadata(context, schema, md, uuid, Integer.parseInt(params.ownerId), group, params.uuid,
                     isTemplate, docType, category, df.format(date), df.format(date), ufo, indexImmediate);

    int iId = Integer.parseInt(id);

         addPrivileges(id, params.getPrivileges(), localGroups, dataMan, context, log);
         context.getBean(MetadataRepository.class).update(iId, new Updater<Metadata>() {
             @Override
             public void apply(@Nonnull Metadata entity) {
                 addCategories(entity, params.getCategories(), localCateg, context, log, null);
             }
         });

         dataMan.setHarvestedExt(iId, params.uuid, Optional.of(params.url));
     dataMan.setTemplate(iId, MetadataType.METADATA, null);

         dataMan.flush();

         //dataMan.indexMetadata(dbms, id); setTemplate update the index
   
    result.addedMetadata++;
   
    // Add Thumbnails only after metadata insertion to avoid concurrent transaction
    // and loaded thumbnails could eventually failed anyway.
    if (params.ogctype.startsWith("WMS") && params.createThumbnails) {
          for (WxSLayerRegistry layer : layersRegistry) {
                loadThumbnail (layer);
            }
        }
  }
 
 
 
  /**
     * Add OperatesOn elements on an ISO19119 metadata
     * 
     *  <srv:operatesOn>
   *    <gmd:MD_DataIdentification uuidref=""/>
   </srv:operatesOn>
    
     * @param md                    iso19119 metadata
     * @param layersRegistry    uuid to be added as an uuidref attribute
     *                  
     */
   private Element addOperatesOnUuid (Element md, List<WxSLayerRegistry> layersRegistry) {
       
    Namespace gmd   = Namespace.getNamespace("gmd", "http://www.isotc211.org/2005/gmd");
    Namespace gco   = Namespace.getNamespace("gco", "http://www.isotc211.org/2005/gco");
    Namespace srv   = Namespace.getNamespace("srv", "http://www.isotc211.org/2005/srv");
        Namespace xlink = Namespace.getNamespace("xlink", "http://www.w3.org/1999/xlink");

        Element root   = md.getChild("identificationInfo", gmd)
              .getChild("SV_ServiceIdentification", srv);


        /*
           * TODO
           *
              For each queryable layer queryable = "1" et /ROOT/Capability/Request/*[name()!='getCapabilities']
                  or queryable = "0" et /ROOT/Capability/Request/*[name()!='getCapabilities' and name!='GetFeatureInfo']
              should do
                  srv:coupledResource/srv:SV_CoupledResource/srv:OperationName = /ROOT/Capability/Request/child::name()
                  srv:coupledResource/srv:SV_CoupledResource/srv:identifier = UUID of the data metadata
                  srv:coupledResource/srv:SV_CoupledResource/gco:ScopedName = Layer/Name
              But is this really useful in ISO19119 ?
           */
   
    if (root != null) {
            if(log.isDebugEnabled()) log.debug("  - add SV_CoupledResource and OperatesOnUuid");
     
      Element couplingType = root.getChild("couplingType", srv);
      int coupledResourceIdx = root.indexOf(couplingType);
     
      for (WxSLayerRegistry layer : layersRegistry)
      {
        // Create coupled resources elements to register all layername
        // in service metadata. This information could be used to add
        // interactive map button when viewing service metadata.
        Element coupledResource = new Element ("coupledResource", srv);
        Element scr = new Element ("SV_CoupledResource", srv);
       
       
        // Create operation according to service type
        Element operation = new Element ("operationName", srv);
        Element operationValue = new Element ("CharacterString", gco);
       
        if (params.ogctype.startsWith("WMS"))
          operationValue.setText("GetMap");
        else if (params.ogctype.startsWith("WFS"))
          operationValue.setText("GetFeature");
        else if (params.ogctype.startsWith("WCS"))
          operationValue.setText("GetCoverage");
        else if (params.ogctype.startsWith("SOS"))
          operationValue.setText("GetObservation");
        operation.addContent(operationValue);
       
        // Create identifier (which is the metadata identifier)
        Element id = new Element ("identifier", srv);
        Element idValue = new Element ("CharacterString", gco);
        idValue.setText(layer.uuid);
        id.addContent(idValue);
       
        // Create scoped name element as defined in CSW 2.0.2 ISO profil
        // specification to link service metadata to a layer in a service.
        Element scopedName = new Element ("ScopedName", gco);
        scopedName.setText(layer.name);
       
        scr.addContent(operation);
        scr.addContent(id);
        scr.addContent(scopedName);
        coupledResource.addContent(scr);
       
        // Add coupled resource before coupling type element
        root.addContent(coupledResourceIdx, coupledResource);
       
       
   
        // Add operatesOn element at the end of identification section.
        Element op = new Element ("operatesOn", srv);
        op.setAttribute("uuidref", layer.uuid);

                String hRefLink =  context.getBean(SettingManager.class).getSiteURL(context) + "/xml.metadata.get?uuid=" + layer.uuid;
                op.setAttribute("href", hRefLink, xlink);

       
        root.addContent(op);
       
      }
    }

   
    return md;
  }

 
  /**
     * Add metadata for a Layer/FeatureType/Coverage element of a GetCapabilities document.
     * This function search for a metadataUrl element (with @type = TC211 and format = text/xml)
     * and try to load the XML document.
     * If failed, then an XSLT is used for creating metadata from the
     * Layer/FeatureType/Coverage element.
     * If loaded document contain an existing uuid, metadata will not be loaded in the catalogue.
     * 
     * @param layer     Layer/FeatureType/Coverage element
     * @param capa    GetCapabilities document
     * 
     * @return          uuid
     *                  
     */
  private WxSLayerRegistry addLayerMetadata (Element layer, Element capa) throws JDOMException
  {
   
    DateFormat df     = new SimpleDateFormat ("yyyy-MM-dd'T'HH:mm:ss");
    Date dt       = new Date ();
    WxSLayerRegistry reg= new WxSLayerRegistry ();
    String schema;
    String mdXml;
    String date     = df.format (dt);
    //--- Loading stylesheet
    String styleSheet   = schemaMan.getSchemaDir(params.outputSchema) +
                Geonet.Path.CONVERT_STYLESHEETS +
                "/OGCWxSGetCapabilitiesto19119/" +
                "/OGC" +
                params.ogctype.substring(0,3) +
                "GetCapabilitiesLayer-to-19139.xsl";
    Element xml     = null;
   
    boolean exist;
    boolean loaded     = false;
   
    if (params.ogctype.substring(0,3).equals("WMS")) {
      Element name;
      if (params.ogctype.substring(3,8).equals("1.3.0")) {
        Namespace wms = Namespace.getNamespace("http://www.opengis.net/wms");
        name = layer.getChild ("Name", wms);
      } else {
        name = layer.getChild ("Name");
      }
      //--- For the moment, skip non-requestable category layers
      if (name == null || name.getValue().trim().equals("")) {
        log.info("  - skipping layer with no name element");
        return null;
      }
      reg.name = name.getValue();
    } else if (params.ogctype.substring(0,3).equals("WFS")) {
      Namespace wfs = Namespace.getNamespace("http://www.opengis.net/wfs");
      reg.name   = layer.getChild ("Name", wfs).getValue ();
    } else if (params.ogctype.substring(0,3).equals("WCS")) {
      Namespace wcs = Namespace.getNamespace("http://www.opengis.net/wcs");
      reg.name   = layer.getChild ("name", wcs).getValue ();
    } else if (params.ogctype.substring(0,3).equals("SOS")) {
      Namespace gml = Namespace.getNamespace("http://www.opengis.net/gml");
      reg.name   = layer.getChild ("name", gml).getValue ();
    }
   
    log.info ("  - Loading layer: " + reg.name);
   
    //--- md5 the full capabilities URL + the layer, coverage or feature name
    reg.uuid = Sha1Encoder.encodeString(this.capabilitiesUrl+"#"+reg.name); // the dataset identifier
 
    //--- Trying loading metadataUrl element
    if (params.useLayerMd && !params.ogctype.substring(0,3).equals("WMS")) {
      log.info("  - MetadataUrl harvester only supported for WMS layers.");
    }
   
    if (params.useLayerMd && params.ogctype.substring(0,3).equals("WMS")) {
     
      Namespace xlink   = Namespace.getNamespace ("http://www.w3.org/1999/xlink");
     
      // Get metadataUrl xlink:href
      // TODO : add support for WCS & WFS metadataUrl element.


            // Check if add namespace prefix to Xpath queries.  If layer.getNamespace() is:
            //    * Namespace.NO_NAMESPACE, should not be added, otherwise exception is launched
            //    * Another namespace, should be added a namespace prefix to Xpath queries, otherwise doesn't find any result
            String dummyNsPrefix = "";
            boolean addNsPrefix = !layer.getNamespace().equals(Namespace.NO_NAMESPACE);
            if (addNsPrefix) dummyNsPrefix = "x:";

            XPath mdUrl     = XPath.newInstance ("./" + dummyNsPrefix + "MetadataURL[@type='TC211' and " + dummyNsPrefix + "Format='text/xml']/" + dummyNsPrefix + "OnlineResource");
            if (addNsPrefix) mdUrl.addNamespace("x", layer.getNamespace().getURI());
            Element onLineSrc   = (Element) mdUrl.selectSingleNode (layer);

            // Check if metadataUrl in WMS 1.3.0 format
            if (onLineSrc == null) {
                mdUrl     = XPath.newInstance ("./" + dummyNsPrefix + "MetadataURL[@type='ISO19115:2003' and " + dummyNsPrefix + "Format='text/xml']/" + dummyNsPrefix + "OnlineResource");
                if (addNsPrefix) mdUrl.addNamespace("x", layer.getNamespace().getURI());
                onLineSrc   = (Element) mdUrl.selectSingleNode (layer);
            }

      if (onLineSrc != null) {
        org.jdom.Attribute href = onLineSrc.getAttribute ("href", xlink);

        if (href != null) {  // No metadataUrl attribute for that layer
          mdXml = href.getValue ();
          try {
            xml = Xml.loadFile (new URL(mdXml));

                        // If url is CSW GetRecordById remove envelope
                        if (xml.getName().equals("GetRecordByIdResponse")) {
                            xml = (Element) xml.getChildren().get(0);
                        }

            schema = dataMan.autodetectSchema (xml, null); // ie. iso19115 or 139 or DC
            // Extract uuid from loaded xml document
            // FIXME : uuid could be duplicate if metadata already exist in catalog
            reg.uuid = dataMan.extractUUID(schema, xml);
            exist = dataMan.existsMetadataUuid(reg.uuid);
           
            if (exist) {
              log.warning("    Metadata uuid already exist in the catalogue. Metadata will not be loaded.");
              result.layerUuidExist ++;
              // Return the layer info even if it exists in order
              // to link to the service record.
              return reg;
            }
           
            if (schema == null) {
              log.warning("    Failed to detect schema from metadataUrl file. Use GetCapabilities document instead for that layer.");
              result.unknownSchema ++;
              loaded = false;
            } else {
              log.info("  - Load layer metadataUrl document ok: " + mdXml);
             
              loaded = true;
              result.layerUsingMdUrl ++;
            }
          // TODO : catch other exception
          }catch (Exception e) {
            log.warning("  - Failed to load layer using metadataUrl attribute : " + e.getMessage());
            loaded = false;
          }
        } else {
          log.info("  - No metadataUrl attribute with format text/xml found for that layer");
          loaded = false;
        }
      } else {
        log.info("  - No OnlineResource found for that layer");
        loaded = false;
      }
    }
   
   
    //--- using GetCapabilities document
    if (!loaded && params.useLayer){
      try {
        //--- set XSL param to filter on layer and set uuid
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("uuid", reg.uuid);
        param.put("Name", reg.name);
        param.put("lang", params.lang);
        param.put("topic", params.topic);
       
        xml = Xml.transform (capa, styleSheet, param);
                if(log.isDebugEnabled()) log.debug("  - Layer loaded using GetCapabilities document.");
       
      } catch (Exception e) {
        log.warning("  - Failed to do XSLT transformation on Layer element : " + e.getMessage());
      }
    }
   
   
    // Insert in db
    try {

            //
            //  insert metadata
            //
            String group = null, isTemplate = null, docType = null, title = null, category = null;
            boolean ufo = false, indexImmediate = false;
           
      schema = dataMan.autodetectSchema (xml);
     
            reg.id = dataMan.insertMetadata(context, schema, xml, reg.uuid, Integer.parseInt(params.ownerId), group, params.uuid,
                         isTemplate, docType, category, date, date, ufo, indexImmediate);

      int iId = Integer.parseInt(reg.id);
            if(log.isDebugEnabled()) log.debug("    - Layer loaded in DB.");

            if(log.isDebugEnabled()) log.debug("    - Set Privileges and category.");
            addPrivileges(reg.id, params.getPrivileges(), localGroups, dataMan, context, log);

            if (params.datasetCategory!=null && !params.datasetCategory.equals("")) {
        dataMan.setCategory (context, reg.id, params.datasetCategory);
            }

            if(log.isDebugEnabled()) log.debug("    - Set Harvested.");
      dataMan.setHarvestedExt(iId, params.uuid, Optional.of(params.url)); // FIXME : harvestUuid should be a MD5 string

            dataMan.flush();

            dataMan.indexMetadata(reg.id, false);
     
      try {
          // Load bbox info for later use (eg. WMS thumbnails creation)
          Namespace gmd   = Namespace.getNamespace("http://www.isotc211.org/2005/gmd");
          Namespace gco   = Namespace.getNamespace("http://www.isotc211.org/2005/gco");
         
          ElementFilter bboxFinder = new ElementFilter("EX_GeographicBoundingBox", gmd);
                @SuppressWarnings("unchecked")
                Iterator<Element> bboxes = xml.getDescendants(bboxFinder);
         
          while (bboxes.hasNext()) {
            Element box = bboxes.next();
            // FIXME : Could be null. Default bbox if from root layer
            reg.minx = Double.valueOf(box.getChild("westBoundLongitude", gmd).getChild("Decimal", gco).getText());
            reg.miny = Double.valueOf(box.getChild("southBoundLatitude", gmd).getChild("Decimal", gco).getText());
            reg.maxx = Double.valueOf(box.getChild("eastBoundLongitude", gmd).getChild("Decimal", gco).getText());
            reg.maxy = Double.valueOf(box.getChild("northBoundLatitude", gmd).getChild("Decimal", gco).getText());
           
          }
      }  catch (Exception e) {
              log.warning("  - Failed to extract layer bbox from metadata : " + e.getMessage());
          }

      result.layer ++;
      log.info("  - metadata loaded with uuid: " + reg.uuid + "/internal id: " + reg.id);
       
    } catch (Exception e) {
      log.warning("  - Failed to load layer metadata : " + e.getMessage());
      result.unretrievable ++;
      return null;
    }
   
    return reg;
  }
 

  /**
     * Call GeoNetwork service to load thumbnails and create small and
     * big ones.
     * 
     * 
     * @param layer   layer for which the thumbnail needs to be generated
     *                  
     */
  private void loadThumbnail (WxSLayerRegistry layer){
        if(log.isDebugEnabled())
            log.debug("  - Creating thumbnail for layer metadata: " + layer.name + " id: " + layer.id);
    Set s = new org.fao.geonet.services.thumbnail.Set ();
   
    try {
      String filename = getMapThumbnail(layer);
     
      if (filename != null) {
                if(log.isDebugEnabled()) log.debug("  - File: " + filename);
       
        Element par = new Element ("request");
        par.addContent(new Element ("id").setText(layer.id));
        par.addContent(new Element ("version").setText("10"));
        par.addContent(new Element ("type").setText("large"));
       
        Element fname = new Element ("fname").setText(filename);
        fname.setAttribute("content-type", "image/png");
        fname.setAttribute("type", "file");
        fname.setAttribute("size", "");
       
        par.addContent(fname);
        par.addContent(new Element ("add").setText("Add"));
        par.addContent(new Element ("createSmall").setText("on"));
        par.addContent(new Element ("smallScalingFactor").setText("180"));
        par.addContent(new Element ("smallScalingDir").setText("width"));
       
        // Call the services
        s.execOnHarvest(par, context, dataMan);

                dataMan.flush();

                result.thumbnails ++;
      } else {
        result.thumbnailsFailed ++;
            }
    } catch (Exception e) {
      log.warning("  - Failed to set thumbnail for metadata: " + e.getMessage());
      e.printStackTrace();
      result.thumbnailsFailed ++;
    }
   
  }
 
  /**
     * Remove thumbnails directory for all metadata
     * FIXME : Do this only for existing one !
     * 
     * @param id   layer for which the thumbnail needs to be generated
     *                  
     */
  private void unsetThumbnail (String id){
        if(log.isDebugEnabled()) log.debug("  - Removing thumbnail for layer metadata: " + id);

    try {
      String file = Lib.resource.getDir(context, Params.Access.PUBLIC, id);
      FileCopyMgr.removeDirectoryOrFile(new File(file));
    } catch (Exception e) {
      log.warning("  - Failed to remove thumbnail for metadata: " + id + ", error: " + e.getMessage());
    }
  }

 
 
  /**
     * Load thumbnails making a GetMap operation.
     * Width is 300px. Ratio is computed for height using LatLongBoundingBoxElement.
     * 
     * 
     * @param layer   layer for which the thumbnail needs to be generated
     *                  
     */
  private String getMapThumbnail (WxSLayerRegistry layer) {
    String filename = layer.uuid + ".png";
    String dir = context.getUploadDir();
    Double r = WIDTH /
            (layer.maxx - layer.minx) *
            (layer.maxy - layer.miny);
   
   
        // Usual GetMap url tested with mapserver and geoserver
    // http://localhost:8080/geoserver/wms?service=WMS&request=GetMap&VERSION=1.1.1&
    //     LAYERS=gn:world&WIDTH=200&HEIGHT=200&FORMAT=image/png&BBOX=-180,-90,180,90&STYLES=
        String crsParamName;
        String bboxParamValue;
        if (params.ogctype.substring(3).equals("1.3.0")) {
            crsParamName = "CRS";
            bboxParamValue = layer.miny + "," +
                    layer.minx + "," +
                    layer.maxy + "," +
                    layer.maxx;
        } else {
            crsParamName = "SRS";
            bboxParamValue = layer.minx + "," +
                    layer.miny + "," +
                    layer.maxx + "," +
                    layer.maxy;
        }
    String url =
            getBaseUrl(params.url) +
            "&SERVICE=" + params.ogctype.substring(0,3) +
            "&VERSION=" + params.ogctype.substring(3) +
            "&REQUEST=" + GETMAP +
            "&FORMAT=" + IMAGE_FORMAT +
            "&WIDTH=" + WIDTH +
            "&" + crsParamName + "=EPSG:4326" +
            "&HEIGHT=" + r.intValue() +
            "&LAYERS=" + layer.name +
            "&STYLES=" +
            "&BBOX=" + bboxParamValue;

        if(log.isDebugEnabled()) log.debug ("Retrieving remote document: " + url);

         HttpGet req = new HttpGet(url);


    try {
        // Connect
            final GeonetHttpRequestFactory requestFactory = context.getBean(GeonetHttpRequestFactory.class);
            final ClientHttpResponse httpResponse = requestFactory.execute(req, new Function<HttpClientBuilder, Void>() {
                @Nullable
                @Override
                public Void apply(@Nullable HttpClientBuilder input) {
                    // set proxy from settings manager
                    Lib.net.setupProxy(context, input);
                    return null//To change body of implemented methods use File | Settings | File Templates.
                }
            });

            if(log.isDebugEnabled()) {
                log.debug("   Get " + httpResponse.getStatusCode());
            }

      if (httpResponse.getStatusCode() == HttpStatus.OK) {
          // Save image document to temp directory
        // TODO: Check OGC exception
                OutputStream fo = null;
                InputStream in = null;
               
                try {
                    fo = new FileOutputStream (dir + filename);
                    in = httpResponse.getBody();
                    BinaryFile.copy (in,fo);
                } finally {
                    IOUtils.closeQuietly(in);
                    IOUtils.closeQuietly(fo);
                }
      } else {
        log.info (" Http error connecting");
        return null;
      }
    } catch (IOException ioe){
      log.info (" Unable to connect to '" + req.toString() + "'");
      log.info (ioe.getMessage());
      return null;
    } finally {
        // Release current connection to the connection pool once you are done
        req.releaseConnection ();
    }
   
    return filename;
  }

  /**
     * Add '?' or '&' if required to url so that parameters can just be
     * appended to it
     *  
     * @param url    Url to which parameters are going to be appended
     *
     */
  private String getBaseUrl(String url) {
    if (url.endsWith("?")) {
      return url;
    } else if (url.contains("?")) {
      return url+"&";
    } else {
      return url+"?";
    }
  }

  //---------------------------------------------------------------------------
  //---
  //--- Variables
  //---
  //---------------------------------------------------------------------------

  private Logger         log;
  private ServiceContext context;
  private OgcWxSParams   params;
  private DataManager    dataMan;
  private SchemaManager  schemaMan;
  private CategoryMapper localCateg;
  private GroupMapper    localGroups;
    private HarvestResult   result;

    /**
   * Store the GetCapabilities operation URL. This URL is scrambled
   * and used to uniquelly identified the service. The idea of generating
   * a uuid based on the URL instead of a randomuuid is to be able later
   * to do an update of the service metadata (which could have been updated
   * in the catalogue) instead of a delete/insert operation.
   */
  private String capabilitiesUrl;
    private static final int WIDTH = 900;
  private static final String GETCAPABILITIES = "GetCapabilities";
  private static final String GETMAP = "GetMap";
    private static final String IMAGE_FORMAT = "image/png";
    private List<WxSLayerRegistry> layersRegistry = new ArrayList<WxSLayerRegistry>();
 
  private static class WxSLayerRegistry {
    public String uuid;
    public String id;
    public String name;
    public Double minx = -180.0;
    public Double miny = -90.0;
    public Double maxx = 180.0;
    public Double maxy = 90.0;
  }

  /* (non-Javadoc)
   * @see org.fao.geonet.kernel.harvest.harvester.IHarvester#getErrors()
   */
  @Override
  public List<HarvestError> getErrors() {
    // TODO Auto-generated method stub
    return null;
  }

}
TOP

Related Classes of org.fao.geonet.kernel.harvest.harvester.ogcwxs.Harvester

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.