/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2011, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotoolkit.processing.datastore.copy; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.sis.util.logging.Logging; import org.opengis.feature.FeatureType; import org.opengis.util.GenericName; import org.opengis.filter.Filter; import org.opengis.filter.expression.PropertyName; import org.opengis.parameter.ParameterValueGroup; import org.apache.sis.internal.feature.AttributeConvention; import org.apache.sis.internal.util.UnmodifiableArrayList; import org.apache.sis.storage.DataStoreException; import org.geotoolkit.data.FeatureStore; import org.geotoolkit.data.FeatureCollection; import org.geotoolkit.data.query.Query; import org.geotoolkit.data.query.QueryBuilder; import org.geotoolkit.data.session.Session; import org.geotoolkit.filter.DefaultPropertyName; import org.geotoolkit.filter.visitor.DuplicatingFilterVisitor; import org.geotoolkit.parameter.Parameters; import org.geotoolkit.processing.AbstractProcess; import org.geotoolkit.process.ProcessException; import org.geotoolkit.version.Version; import org.geotoolkit.version.VersioningException; import static org.geotoolkit.parameter.Parameters.*; import static org.geotoolkit.processing.datastore.copy.CopyDescriptor.*; /** * Copy feature from one datastore to another. * * @author Johann Sorel (Geomatys) * @author Cédric Briançon (Geomatys) * @author Quentin Boileau (Geomatys) * @module */ public class Copy extends AbstractProcess { private static Logger LOGGER = Logging.getLogger("org.geotoolkit.processing.datastore.copy"); /** * Default constructor */ public Copy(final ParameterValueGroup input) { super(INSTANCE,input); } /** * {@inheritDoc } */ @Override protected void execute() throws ProcessException { final FeatureStore sourceDS = value(SOURCE_STORE, inputParameters); final FeatureStore targetDS = value(TARGET_STORE, inputParameters); Session targetSS = value(TARGET_SESSION, inputParameters); final Boolean eraseParam = value(ERASE, inputParameters); final Boolean newVersion = value(NEW_VERSION, inputParameters); // Type name can be removed, it's embedded in the query param. final String typenameParam = value(TYPE_NAME, inputParameters); final Query queryParam = value(QUERY, inputParameters); final boolean doCommit = targetSS == null; final Session sourceSS = sourceDS.createSession(false); if (targetSS == null) { if (targetDS != null) { targetSS = targetDS.createSession(true); } else { throw new ProcessException("Input target_session or target_datastore missing.", this, null); } } boolean reBuildQuery = false; final String queryName; if (queryParam != null) { queryName = queryParam.getTypeName(); reBuildQuery = true; } else if (typenameParam != null) { queryName = typenameParam; } else { queryName = "*"; } final Set<GenericName> names; if ("*".equals(queryName)) { //all values try { names = sourceDS.getNames(); } catch (DataStoreException ex) { throw new ProcessException(ex.getMessage(), this, ex); } } else { //pick only the wanted names names = new HashSet<>(); final List<String> wanted = UnmodifiableArrayList.wrap(queryName.split(",")); for(String s : wanted) { try{ final FeatureType type = sourceDS.getFeatureType(s); names.add(type.getName()); } catch (DataStoreException ex) { throw new ProcessException(ex.getMessage(), this, ex); } } } final float size = names.size(); int inc = 0; for (GenericName n : names) { fireProgressing("Copying "+n+".", (int)((inc*100f)/size), false); try { Query query; if (reBuildQuery) { QueryBuilder builder = new QueryBuilder(queryParam); builder.setTypeName(n); query = builder.buildQuery(); } else { query = queryParam != null ? queryParam : QueryBuilder.all(n); } insert(n, sourceSS, targetSS, query, eraseParam, newVersion); } catch (DataStoreException ex) { throw new ProcessException(ex.getMessage(), this, ex); } inc++; } try { Date lastVersionDate = null; if (doCommit) { LOGGER.log(Level.INFO, "Commit all changes"); targetSS.commit(); //find last version for (GenericName n : names) { if(targetSS.getFeatureStore().getQueryCapabilities().handleVersioning()) { final List<Version> versions = targetSS.getFeatureStore().getVersioning(n.toString()).list(); if (!versions.isEmpty()) { if (lastVersionDate == null || versions.get(versions.size()-1).getDate().getTime() > lastVersionDate.getTime()) { lastVersionDate = versions.get(versions.size()-1).getDate(); } } } } } if(lastVersionDate != null) { Parameters.getOrCreate(VERSION, outputParameters).setValue(lastVersionDate); } } catch (DataStoreException ex) { throw new ProcessException(ex.getMessage(), this, ex); } catch (VersioningException ex) { throw new ProcessException(ex.getMessage(), this, ex); } } private void insert(GenericName name, final Session sourceSS, final Session targetSS, Query query, final boolean erase, final boolean newVersion) throws DataStoreException{ FeatureType type = sourceSS.getFeatureStore().getFeatureType(name.toString()); //Change * to featureType default geometry name if (query != null && query.getFilter() != null) { final Filter newFilter = (Filter) query.getFilter().accept(new BBOXFilterVisitor(), type); final QueryBuilder builder = new QueryBuilder(query); builder.setFilter(newFilter); query = builder.buildQuery(); } final FeatureCollection collection = sourceSS.getFeatureCollection(query); //get the real FeatureType of collection (in case of reprojection, CRS is different). type = collection.getFeatureType(); if(targetSS.getFeatureStore().getNames().contains(name)) { //ERASE if(erase) { targetSS.getFeatureStore().deleteFeatureType(name.toString()); targetSS.getFeatureStore().createFeatureType(type); } }else{ targetSS.getFeatureStore().createFeatureType(type); } //get the created name, namespace might change name = targetSS.getFeatureStore().getFeatureType(type.getName().tip().toString()).getName(); if (targetSS.getFeatureStore().getQueryCapabilities().handleVersioning()) { try { targetSS.getFeatureStore().getVersioning(name.toString()).startVersioning(); } catch (VersioningException ex) { throw new DataStoreException(ex.getLocalizedMessage(), ex); } } //NEW VERSION (remove old features) if (newVersion) { targetSS.removeFeatures(name.toString(), Filter.INCLUDE); } //Logging final StringBuilder logMsg = new StringBuilder("Insert "); logMsg.append(collection.size()).append(" features "); logMsg.append("in type ").append(name.tip().toString()); logMsg.append(" ["); if (erase) { logMsg.append("ERASE"); if (newVersion) logMsg.append(", NEWVERSION"); } if (newVersion) logMsg.append("NEWVERSION"); logMsg.append("]"); LOGGER.log(Level.INFO, logMsg.toString()); //APPEND targetSS.addFeatures(name.toString(), collection); } /** * Override BBox filters if property name equals to * to set name form * default geometry name in given FeatureType. */ private class BBOXFilterVisitor extends DuplicatingFilterVisitor { @Override public Object visit(PropertyName expression, Object extraData) { if ("*".equals(expression.getPropertyName()) && extraData instanceof FeatureType) { return new DefaultPropertyName(((FeatureType) extraData).getProperty(AttributeConvention.GEOMETRY_PROPERTY.toString()).getName().tip().toString()); } return super.visit(expression, extraData); } } }