Package org.fao.geonet.kernel

Source Code of org.fao.geonet.kernel.ThesaurusManager$InitThesauriTableTask

//===  Copyright (C) 2001-2005 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//===
//===  Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
//===  Rome - Italy. email: GeoNetwork@fao.org
//==============================================================================

package org.fao.geonet.kernel;

import org.fao.geonet.kernel.setting.SettingManager;
import org.fao.geonet.utils.IO;
import org.fao.geonet.utils.Log;
import org.fao.geonet.utils.Xml;
import jeeves.server.context.ServiceContext;
import org.fao.geonet.Util;
import jeeves.xlink.Processor;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import org.fao.geonet.constants.Geonet;
import org.fao.geonet.domain.Metadata;
import org.fao.geonet.kernel.oaipmh.Lib;

import org.fao.geonet.repository.MetadataRepository;
import org.jdom.Element;

import org.openrdf.sesame.Sesame;
import org.openrdf.sesame.config.ConfigurationException;
import org.openrdf.sesame.config.RepositoryConfig;
import org.openrdf.sesame.config.SailConfig;
import org.openrdf.sesame.constants.RDFFormat;
import org.openrdf.sesame.repository.local.LocalRepository;
import org.openrdf.sesame.repository.local.LocalService;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//=============================================================================
public class ThesaurusManager implements ThesaurusFinder {

  private ConcurrentHashMap<String, Thesaurus> thesauriMap = new ConcurrentHashMap<String, Thesaurus>();
  private LocalService service = null;
  private String thesauriDirectory = null;
    private boolean initialized = false;


    /**
   * Initialize ThesaurusManager.
   *
     * @param context ServiceContext used to check when servlet is up only
     * @param appPath to find conversion XSLTs etc
     * @param thesauriRepository
     * @throws Exception
   */
  public synchronized void init(ServiceContext context, String appPath, String thesauriRepository)
      throws Exception {
        if (this.initialized) {
            return;
        }
        this.initialized = true;
    // Get Sesame interface
    service = Sesame.getService();

    File thesauriDir = new File(thesauriRepository);

    if (!thesauriDir.exists()) {
      thesauriDir = new File(appPath + thesauriDir);
        }

        thesauriDir = thesauriDir.getAbsoluteFile();
    thesauriDirectory = thesauriDir.getAbsolutePath();

    batchBuildTable(context, thesauriDir);
  }
 
  /**
   * Start task to build thesaurus table once the servlet is up.
   *
   * @param context ServiceContext used to check when servlet is up only
   * @param thesauriDir directory containing thesauri
   */
  private void batchBuildTable(ServiceContext context, File thesauriDir) {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    try {
      Runnable worker = new InitThesauriTableTask(context, thesauriDir);
      executor.execute(worker);
    } finally {
      executor.shutdown();
    }
  }

  /**
   * A Task to build the thesaurus table once the servlet is up.
   * Since thesauri can be metadata records (registers) they can also have
   * xlinks. These may not be resolveable until the servlet is up. Hence
   * we start a thread that waits until the servlet is up before reading
   * the thesauri and creating the thesaurus table.
   */
  final class InitThesauriTableTask implements Runnable {

    private final ServiceContext context;
    private final File thesauriDir;

    InitThesauriTableTask(ServiceContext context, File thesauriDir) {
      this.context = context;
      this.thesauriDir = thesauriDir;
    }

    public void run() {
      context.setAsThreadLocal();
      try {
        // poll context to see whether servlet is up yet
        while (!context.isServletInitialized()) {
          if (Log.isDebugEnabled(Geonet.THESAURUS_MAN))
            Log.debug(Geonet.THESAURUS_MAN, "Waiting for servlet to finish initializing..");
          Thread.sleep(10000); // sleep 10 seconds
        }
        try {
          initThesauriTable(thesauriDir, context);
        } catch (Exception e) {
          Log.error(Geonet.THESAURUS_MAN, "Error rebuilding thesaurus table : "+e.getMessage()+"\n"+ Util.getStackTrace(e));
        }
      } catch (Exception e) {
        Log.debug(Geonet.THESAURUS_MAN, "Thesaurus table rebuilding thread threw exception");
        e.printStackTrace();
      }
    }
  }

  /**
   *
   * @param thesauriDirectory
   */
  private void initThesauriTable(File thesauriDirectory, ServiceContext context) {

    thesauriMap = new ConcurrentHashMap<String,Thesaurus>();
    Log.info(Geonet.THESAURUS_MAN,"Scanning "+thesauriDirectory);

    if (thesauriDirectory.isDirectory()) {
      // init of external repositories
      File externalThesauriDirectory = new File(thesauriDirectory,
          Geonet.CodeList.EXTERNAL + File.separator + Geonet.CodeList.THESAURUS);
      if (externalThesauriDirectory.isDirectory()) {
        File[] rdfDataDirectory = externalThesauriDirectory.listFiles();
                for (File aRdfDataDirectory : rdfDataDirectory) {
                    if (aRdfDataDirectory.isDirectory()) {
                        loadRepositories(aRdfDataDirectory, Geonet.CodeList.EXTERNAL, context);
                    }
                }
      }

      // init of local repositories
      File localThesauriDirectory = new File(thesauriDirectory, Geonet.CodeList.LOCAL
          + File.separator + Geonet.CodeList.THESAURUS);
      if (localThesauriDirectory.isDirectory()) {
        File[] rdfDataDirectory = localThesauriDirectory.listFiles();
                for (File aRdfDataDirectory : rdfDataDirectory) {
                    if (aRdfDataDirectory.isDirectory()) {
                        loadRepositories(aRdfDataDirectory, Geonet.CodeList.LOCAL, context);
                    }
                }
      }

      // init of register repositories
      File registerThesauriDirectory = new File(thesauriDirectory, Geonet.CodeList.REGISTER
          + File.separator + Geonet.CodeList.THESAURUS);
      if (registerThesauriDirectory.isDirectory()) {
        File[] rdfDataDirectory = registerThesauriDirectory.listFiles();
                for (File aRdfDataDirectory : rdfDataDirectory) {
                    if (aRdfDataDirectory.isDirectory()) {
                        loadRepositories(aRdfDataDirectory, Geonet.CodeList.REGISTER, context);
                    }
                }
      }
    }
  }

  /**
   *
   * @param thesauriDirectory
   */
  private void loadRepositories(File thesauriDirectory, String root, ServiceContext context) {
   
    FilenameFilter filter = new FilenameFilter() {
      public boolean accept(File dir, String name) {
        return name.endsWith(".rdf");
      }
    };

    String[] rdfDataFile = thesauriDirectory.list(filter);
        final String siteURL = context.getBean(SettingManager.class).getSiteURL(context);

        for (String aRdfDataFile : rdfDataFile) {

            Thesaurus gst = null;
            if (root.equals(Geonet.CodeList.REGISTER)) {
                if (Log.isDebugEnabled(Geonet.THESAURUS_MAN))
                    Log.debug(Geonet.THESAURUS_MAN, "Creating thesaurus : " + aRdfDataFile);

                File outputRdf = new File(thesauriDirectory, aRdfDataFile);
                String uuid = StringUtils.substringBefore(aRdfDataFile, ".rdf");
                try {
                    FileOutputStream outputRdfStream = new FileOutputStream(outputRdf);
                    getRegisterMetadataAsRdf(uuid, outputRdfStream, context);
                    outputRdfStream.close();
                } catch (Exception e) {
                    Log.error(Geonet.THESAURUS_MAN, "Register thesaurus " + aRdfDataFile + " could not be read/converted from ISO19135 "
                                                    + "record in catalog - skipping");
                    e.printStackTrace();
                    continue;
                }

                gst = new Thesaurus(context.getApplicationContext(), aRdfDataFile, root, thesauriDirectory.getName(), outputRdf, siteURL);

            } else {
                gst = new Thesaurus(context.getApplicationContext(), aRdfDataFile, root, thesauriDirectory.getName(), new File(thesauriDirectory, aRdfDataFile), siteURL);
            }

            try {
                addThesaurus(gst, false);
            } catch (Exception e) {
                e.printStackTrace();
                // continue loading
            }
        }
    }

  /** 
   * Get ISO19135 Register Metadata from catalog and convert to rdf.  
   *
   * @param uuid Uuid of register (ISO19135) metadata record describing thesaurus
   * @param os OutputStream to write rdf to from XSLT conversion
   */
  private void getRegisterMetadataAsRdf(String uuid, OutputStream os, ServiceContext context) throws Exception {
        Metadata mdInfo = context.getBean(MetadataRepository.class).findOneByUuid(uuid);
        Integer id = mdInfo.getId();
        final DataManager dataManager = context.getBean(DataManager.class);
        Element md = dataManager.getMetadata("" + id);
        Processor.detachXLink(md, context);
        final String siteURL = context.getBean(SettingManager.class).getSiteURL(context);
        Element env = Lib.prepareTransformEnv(mdInfo.getUuid(), mdInfo.getDataInfo().getChangeDate().getDateAndTime(),
                "", siteURL, "");

        //--- transform the metadata with the created env and specified stylesheet
        Element root = new Element("root");
        root.addContent(md);
        root.addContent(env);

        String styleSheet = dataManager.getSchemaDir("iso19135") + "convert/" + Geonet.File.EXTRACT_SKOS_FROM_ISO19135;
        Xml.transform(root, styleSheet, os);
  }

  /**
   * Build thesaurus file path according to thesaurus configuration (ie. codelist directory location).
   * If directory does not exist, it will create it.
   *
   * @param fname
   * @param type
   * @param dname
   *
   * @return the thesaurus file path.
   */
  public String buildThesaurusFilePath(String fname, String type, String dname) throws IOException {
    String dirPath = thesauriDirectory + File.separator + type + File.separator + Geonet.CodeList.THESAURUS + File.separator + dname;
    File dir = new File(dirPath);
    IO.mkdirs(dir, "Thesaurus dname specific directory");
    return dirPath + File.separator + fname;
 

  /**
   *
   * @param gst
   * @param writeTitle TODO
   */
  public void addThesaurus(Thesaurus gst, boolean writeTitle) throws Exception {

    String thesaurusName = gst.getKey();

        if(Log.isDebugEnabled(Geonet.THESAURUS_MAN))
            Log.debug(Geonet.THESAURUS_MAN, "Adding thesaurus : "+ thesaurusName);

    if (existsThesaurus(thesaurusName)) {
      throw new Exception ("A thesaurus exists with code " + thesaurusName);
    }
   
    createThesaurusRepository(gst);
    thesauriMap.put(thesaurusName, gst);
   
    if (writeTitle) {
        gst.addTitleElement(gst.getTitle());
    }

  }
 
  /**
   *
   * @param name
   */
  public void remove(String name){
    service.removeRepository(name);
    thesauriMap.remove(name);
  }
 
  /**
   *
   * @param gst
   */
  private void createThesaurusRepository(Thesaurus gst) throws Exception {
    LocalRepository thesaurusRepository;
    try {
      RepositoryConfig repConfig = new RepositoryConfig(gst.getKey());

      SailConfig syncSail = new SailConfig("org.openrdf.sesame.sailimpl.sync.SyncRdfSchemaRepository");
      SailConfig memSail = new org.openrdf.sesame.sailimpl.memory.RdfSchemaRepositoryConfig(
                                                         gst.getFile().getAbsolutePath(), RDFFormat.RDFXML);
      repConfig.addSail(syncSail);
      repConfig.addSail(memSail);
      repConfig.setWorldReadable(true);
      repConfig.setWorldWriteable(true);
     
      thesaurusRepository = service.createRepository(repConfig);

      gst.setRepository(thesaurusRepository);
    } catch (ConfigurationException e) {
      e.printStackTrace();
      throw e;
    }      
  }
     
  // =============================================================================
  // PUBLIC SERVICES

  public String getThesauriDirectory() {
    return thesauriDirectory;
  }
 
  @Override
    public Map<String, Thesaurus> getThesauriMap() {
    return Collections.unmodifiableMap(thesauriMap);
  }

    @Override
    public Thesaurus getThesaurusByName(String thesaurusName) {
    return thesauriMap.get(thesaurusName);
 

  /**
   * @param name
   * @return
   */
  @Override
    public boolean existsThesaurus(String name) {
    return (thesauriMap.get(name) != null);
  }

  /**
   * Create (or update an existing) rdf thesaurus from the specified ISO19135
   * register record.
   *
   * @param uuid Uuid of iso19135 register metadata record to update thesaurus
   * @param type Type of thesaurus (theme, etc)
   * @return id of thesaurus created/updated
   */
  public String createUpdateThesaurusFromRegister(String uuid, String type, ServiceContext context) throws Exception {

    String aRdfDataFile;
    String root = Geonet.CodeList.REGISTER;

    // check whether we have created a thesaurus for this register already
    aRdfDataFile = uuid+".rdf";
        String thesaurusFile = buildThesaurusFilePath(aRdfDataFile, root, type);
        File outputRdf = new File(thesaurusFile);
        final String siteURL = context.getBean(SettingManager.class).getSiteURL(context);
        Thesaurus gst = new Thesaurus(context.getApplicationContext(), aRdfDataFile, root, type, outputRdf, siteURL);

    FileOutputStream outputRdfStream = null;
    try {
            outputRdfStream = new FileOutputStream(outputRdf);
      getRegisterMetadataAsRdf(uuid, outputRdfStream, context);
    } catch (Exception e) {
      Log.error(Geonet.THESAURUS_MAN, "Register thesaurus "+aRdfDataFile+" could not be read/converted from ISO19135 record in catalog - skipping");
      e.printStackTrace();
    } finally {
        IOUtils.closeQuietly(outputRdfStream);
    }

    String theKey = gst.getKey();
    gst.retrieveThesaurusTitle();

    if (thesauriMap.replace(theKey, gst) == null) {
      createThesaurusRepository(gst);
      thesauriMap.put(theKey, gst);
            if(Log.isDebugEnabled(Geonet.THESAURUS_MAN))
                Log.debug(Geonet.THESAURUS_MAN, "Created thesaurus "+theKey+" from register "+uuid);
    } else {
      service.removeRepository(theKey);
      createThesaurusRepository(gst);
            if(Log.isDebugEnabled(Geonet.THESAURUS_MAN))
                Log.debug(Geonet.THESAURUS_MAN, "Rebuilt thesaurus "+theKey+" from register "+uuid);
    }

    return theKey;
  }

}
TOP

Related Classes of org.fao.geonet.kernel.ThesaurusManager$InitThesauriTableTask

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.