org.fao.geonet.MetadataResourceDatabaseMigration.java Source code

Java tutorial

Introduction

Here is the source code for org.fao.geonet.MetadataResourceDatabaseMigration.java

Source

/*
 * =============================================================================
 * ===   Copyright (C) 2001-2016 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;

import com.google.common.collect.Lists;

import org.apache.commons.lang.StringUtils;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.kernel.setting.SettingManager;
import org.fao.geonet.schema.iso19139.ISO19139Namespaces;
import org.fao.geonet.utils.Log;
import org.fao.geonet.utils.Xml;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/**
 * Replace old metadata link to uploaded file by new API.
 * Only applies to ISO19139 graphic overview and online resources.
 *
 * http://localhost:8080/geonetwork/srv/en/resources.get?uuid=da165110-88fd-11da-a88f-000d939bc5d8&fname=basins.zip&access=private
 *
 * is replaced by
 *
 * http://localhost:8080/geonetwork/srv/api/metadata/da165110-88fd-11da-a88f-000d939bc5d8/resources/basins.zip
 *
 *
 * Created by francois on 12/01/16.
 */
public class MetadataResourceDatabaseMigration extends DatabaseMigrationTask {

    private static final ArrayList<Namespace> NAMESPACES = Lists.newArrayList(ISO19139Namespaces.GMD,
            ISO19139Namespaces.GCO);

    private static final String XPATH_RESOURCES = "*//*[contains(text(), '/resources.get?')]";
    private static final String XPATH_THUMBNAIL_WITH_NO_URL = "*//gmd:MD_BrowseGraphic"
            + "[gmd:fileDescription/gco:CharacterString = 'thumbnail' or "
            + "gmd:fileDescription/gco:CharacterString = 'large_thumbnail']/gmd:fileName/"
            + "gco:CharacterString[not(starts-with(normalize-space(text()), 'http'))]";
    private static final String XPATH_THUMBNAIL_WITH_URL = "*//gmd:graphicOverview/gmd:MD_BrowseGraphic[gmd:fileDescription/gco:CharacterString]/gmd:fileName/gco:CharacterString[starts-with(normalize-space(text()), 'http')]";
    private static final String XPATH_ATTACHMENTS_WITH_URL = "*//gmd:CI_OnlineResource[gmd:protocol/gco:CharacterString = 'WWW:DOWNLOAD-1.0-http--download']/gmd:linkage/gmd:URL";

    private static final Pattern pattern = Pattern.compile(
            "(.*)\\/([a-zA-Z0-9_\\-]+)\\/([a-z]{2,3})\\/{1,2}resources.get\\?.*fname=([\\p{L}\\w\\s\\.\\-]+)(&.*|$)");

    public static boolean updateMetadataResourcesLink(@Nonnull Element xml, @Nullable String uuid,
            SettingManager settingManager) throws JDOMException {
        boolean changed = false;

        if (uuid == null) {
            final Element uuidElement = Xml.selectElement(xml, "gmd:fileIdentifier/gco:CharacterString",
                    NAMESPACES);
            if (uuidElement != null) {
                uuid = uuidElement.getText();
            }
        }

        if (StringUtils.isNotEmpty(uuid)) {
            @SuppressWarnings("unchecked")
            final List<Element> links = Lists
                    .newArrayList((Iterable<? extends Element>) Xml.selectNodes(xml, XPATH_RESOURCES));

            for (Element element : links) {
                final String url = element.getText();
                Matcher regexMatcher = pattern.matcher(url);
                element.setText(regexMatcher
                        .replaceAll(settingManager.getNodeURL() + "api/records/" + uuid + "/attachments/$4"));
                changed = true;
            }

            // ATTACHMENTS
            // This fix the imports of metadata with attachments
            @SuppressWarnings("unchecked")
            final List<Element> linksAttachmentsUrl = Lists.newArrayList(
                    (Iterable<? extends Element>) Xml.selectNodes(xml, XPATH_ATTACHMENTS_WITH_URL, NAMESPACES));

            for (Element element : linksAttachmentsUrl) {
                final String url = element.getText();
                if (url.indexOf("api/records/") > 0) {
                    element.setText(url.replace(url.substring(0, url.indexOf("api/records/")),
                            settingManager.getNodeURL()));
                    changed = true;
                }
            }

            // THUMBNAILS
            // This fix the imports from older versions of GN
            // where the thumbnails contains just the filename
            @SuppressWarnings("unchecked")
            final List<Element> linksThumbnailsNoUrl = Lists.newArrayList(
                    (Iterable<? extends Element>) Xml.selectNodes(xml, XPATH_THUMBNAIL_WITH_NO_URL, NAMESPACES));

            for (Element element : linksThumbnailsNoUrl) {
                final String filename = element.getText();
                element.setText(String.format("%sapi/records/" + uuid + "/attachments/%s",
                        settingManager.getNodeURL(), filename));
                changed = true;
            }

            // This fix the imports from current versions of GN
            // where the thumbnails contains the full URL of the resource
            @SuppressWarnings("unchecked")
            final List<Element> linksThumbnailsWithUrl = Lists.newArrayList(
                    (Iterable<? extends Element>) Xml.selectNodes(xml, XPATH_THUMBNAIL_WITH_URL, NAMESPACES));

            for (Element element : linksThumbnailsWithUrl) {
                final String url = element.getText();
                if (url.indexOf("api/records/") > 0) {
                    element.setText(url.replace(url.substring(0, url.indexOf("api/records/")),
                            settingManager.getNodeURL()));
                    changed = true;
                }
            }
        } else {
            throw new UnsupportedOperationException("Metadata is not supported. UUID is not defined.");
        }
        return changed;
    }

    @Override
    public void update(Connection connection) throws SQLException {
        Log.debug(Geonet.DB, "MetadataResourceDatabaseMigration");

        try (PreparedStatement update = connection.prepareStatement("UPDATE metadata SET data=? WHERE id=?")) {
            try (Statement statement = connection.createStatement();
                    ResultSet resultSet = statement
                            .executeQuery("SELECT data,id,uuid FROM metadata WHERE isharvested = 'n'")) {
                int numInBatch = 0;
                final SettingManager settingManager = applicationContext.getBean(SettingManager.class);

                while (resultSet.next()) {
                    final Element xml = Xml.loadString(resultSet.getString(1), false);
                    final int id = resultSet.getInt(2);
                    final String uuid = resultSet.getString(3);
                    boolean changed = updateMetadataResourcesLink(xml, uuid, settingManager);
                    if (changed) {
                        String updatedData = Xml.getString(xml);
                        update.setString(1, updatedData);
                        update.setInt(2, id);
                        update.addBatch();
                        numInBatch++;
                        if (numInBatch > 200) {
                            update.executeBatch();
                            numInBatch = 0;
                        }
                    }
                }
                update.executeBatch();
            } catch (java.sql.BatchUpdateException e) {
                System.out.println("Error occurred while updating resource links:");
                e.printStackTrace();
                SQLException next = e.getNextException();
                while (next != null) {
                    System.err.println("Next error: ");
                    next.printStackTrace();
                    next = e.getNextException();
                }

                throw new RuntimeException(e);
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }
}