//$HeadURL$
/*----------------------------------------------------------------------------
This file is part of deegree, http://deegree.org/
Copyright (C) 2001-2009 by:
- Department of Geography, University of Bonn -
and
- lat/lon GmbH -
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; either version 2.1 of the License, or (at your option)
any later version.
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.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Contact information:
lat/lon GmbH
Aennchenstr. 19, 53177 Bonn
Germany
http://lat-lon.de/
Department of Geography, University of Bonn
Prof. Dr. Klaus Greve
Postfach 1147, 53001 Bonn
Germany
http://www.geographie.uni-bonn.de/deegree/
e-mail: info@deegree.org
----------------------------------------------------------------------------*/
package org.deegree.igeo.commands.model;
import static java.util.Collections.singletonList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.deegree.datatypes.QualifiedName;
import org.deegree.framework.log.ILogger;
import org.deegree.framework.log.LoggerFactory;
import org.deegree.framework.util.Pair;
import org.deegree.igeo.config.EnvelopeType;
import org.deegree.igeo.config.MemoryDatasourceType;
import org.deegree.igeo.config.LayerType.MetadataURL;
import org.deegree.igeo.dataadapter.FeatureAdapter;
import org.deegree.igeo.dataadapter.LinkedTable;
import org.deegree.igeo.i18n.Messages;
import org.deegree.igeo.mapmodel.Datasource;
import org.deegree.igeo.mapmodel.Layer;
import org.deegree.igeo.mapmodel.MapModel;
import org.deegree.igeo.mapmodel.MemoryDatasource;
import org.deegree.kernel.AbstractCommand;
import org.deegree.kernel.Command;
import org.deegree.model.Identifier;
import org.deegree.model.feature.Feature;
import org.deegree.model.feature.FeatureCollection;
import org.deegree.model.feature.FeatureFactory;
import org.deegree.model.feature.FeatureProperty;
import org.deegree.model.feature.schema.FeatureType;
import org.deegree.model.feature.schema.PropertyType;
import org.deegree.model.spatialschema.Envelope;
/**
* {@link Command} implementation for linking an external table (Excel, CSV, database) to a layer
*
* @author <a href="mailto:name@deegree.org">Andreas Poth</a>
* @author last edited by: $Author$
*
* @version $Revision$, $Date$
*/
public class LinkTableCommand extends AbstractCommand {
private static final QualifiedName name = new QualifiedName( "Link Table Command" );
private static final ILogger LOG = LoggerFactory.getLogger( LinkTableCommand.class );
private Layer resultLayer;
private Layer sourceLayer;
private LinkedTable linkedTable;
private MapModel mm;
private boolean view = false;
private String title;
/**
* @param linkedTable
* the linkedTable to set
*/
public void setLinkedTable( LinkedTable linkedTable ) {
this.linkedTable = linkedTable;
}
/**
*
* @param mapModel
*/
public void setMapModel( MapModel mapModel ) {
this.mm = mapModel;
this.sourceLayer = mm.getLayersSelectedForAction( MapModel.SELECTION_ACTION ).get( 0 );
}
/**
*
* @param view
*/
public void setView( boolean view ) {
this.view = view;
}
/**
* @param title
*/
public void setLayerTitle( String title ) {
this.title = title;
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#execute()
*/
public void execute()
throws Exception {
if ( view ) {
String abstract_ = "created from layer " + sourceLayer.getTitle() + " and table " + linkedTable.getTitle();
List<Datasource> datasources = sourceLayer.getDatasources();
datasources.get( 0 ).addLinkedTable( linkedTable.getLinkedTableType() );
resultLayer = new Layer( mm, new Identifier( title ), title, abstract_, datasources,
new ArrayList<MetadataURL>() );
resultLayer.setEditable( false );
resultLayer.setMinScaleDenominator( sourceLayer.getMinScaleDenominator() );
resultLayer.setMaxScaleDenominator( sourceLayer.getMaxScaleDenominator() );
mm.insert( resultLayer, sourceLayer.getParent(), sourceLayer, false );
} else {
linkAsNewLayer();
}
}
/**
*
* @throws Exception
*/
void linkAsNewLayer()
throws Exception {
FeatureType ft = createFeatureType();
FeatureAdapter adapter = (FeatureAdapter) sourceLayer.getDataAccess().get( 0 );
Envelope env = adapter.getDatasource().getExtent();
MemoryDatasourceType mdst = new MemoryDatasourceType();
EnvelopeType et = new EnvelopeType();
et.setMinx( env.getMin().getX() );
et.setMiny( env.getMin().getY() );
et.setMaxx( env.getMax().getX() );
et.setMaxy( env.getMax().getY() );
et.setCrs( mm.getEnvelope().getCoordinateSystem().getPrefixedName() );
mdst.setExtent( et );
FeatureCollection fc = createFeatureCollection( ft );
if ( fc.size() > 0 ) {
Datasource ds = new MemoryDatasource( mdst, null, null, fc );
String abstract_ = "created from layer " + sourceLayer.getTitle() + " and table " + linkedTable.getTitle();
resultLayer = new Layer( mm, new Identifier( title ), title, abstract_, singletonList( ds ),
Collections.<MetadataURL> emptyList() );
resultLayer.setEditable( true );
resultLayer.setMinScaleDenominator( sourceLayer.getMinScaleDenominator() );
resultLayer.setMaxScaleDenominator( sourceLayer.getMaxScaleDenominator() );
mm.insert( resultLayer, sourceLayer.getParent(), sourceLayer, false );
} else {
LOG.logWarning( "not matching set of keys found; no new layer will be created" );
}
}
/**
* @return feature collection as merge of feature collection assigned to sourceLayer and linkedTable
*/
@SuppressWarnings("unchecked")
private FeatureCollection createFeatureCollection( FeatureType ft )
throws Exception {
FeatureAdapter adapter = (FeatureAdapter) sourceLayer.getDataAccess().get( 0 );
FeatureCollection layerFC = adapter.getFeatureCollection();
FeatureCollection fc = FeatureFactory.createFeatureCollection( "UUID_" + UUID.randomUUID().toString(),
layerFC.size() * 2 );
List<Pair<QualifiedName, String>> relationKeys = linkedTable.getRelationKeys();
Pair<String, Object>[] key = new Pair[relationKeys.size()];
for ( int i = 0; i < layerFC.size(); i++ ) {
Feature feature = layerFC.getFeature( i );
// created (multiple) key for selecting table row(s) assigned to current feature
for ( int j = 0; j < key.length; j++ ) {
Object value = feature.getDefaultProperty( relationKeys.get( j ).first ).getValue();
key[j] = new Pair<String, Object>( relationKeys.get( j ).second, value );
}
// read tables rows assigned to current feature
// TODO
// read data from database in blocks to avoid performing hundreds and thousands
// of SQL statements
Object[][] rows = linkedTable.getRows( key );
if ( rows.length > 0 ) {
// create a new feature for each matching row
String table = linkedTable.getLinkedTableType().getTitle();
FeatureType layerFt = adapter.getSchema();
String[] column = linkedTable.getColumnNames();
for ( int j = 0; j < rows.length; j++ ) {
FeatureProperty[] fp = new FeatureProperty[ft.getProperties().length];
FeatureProperty[] fps = feature.getProperties();
int c = 0;
for ( int k = 0; k < fps.length; k++ ) {
Object v = feature.getDefaultProperty( fps[k].getName() ).getValue();
fp[c++] = FeatureFactory.createFeatureProperty( fps[k].getName(), v );
}
for ( int k = 0; k < column.length; k++ ) {
try {
QualifiedName qn = new QualifiedName( column[k] + "_" + table, layerFt.getNameSpace() );
fp[c++] = FeatureFactory.createFeatureProperty( qn, rows[j][k] );
} catch ( Exception e ) {
throw new Exception(
Messages.getMessage(
sourceLayer.getOwner().getApplicationContainer().getLocale(),
"$MD11612" ) );
}
}
fc.add( FeatureFactory.createFeature( "UUID_" + UUID.randomUUID().toString(), ft, fp ) );
}
}
}
return fc;
}
/**
* @return
*/
private FeatureType createFeatureType() {
FeatureAdapter adapter = (FeatureAdapter) sourceLayer.getDataAccess().get( 0 );
FeatureType layerFt = adapter.getSchema();
PropertyType[] layerPt = layerFt.getProperties();
String table = linkedTable.getLinkedTableType().getTitle();
String[] column = linkedTable.getColumnNames();
int[] types = linkedTable.getColumnTypes();
PropertyType[] allPt = new PropertyType[layerPt.length + column.length];
int c = 0;
for ( int i = 0; i < layerPt.length; i++ ) {
allPt[c++] = layerPt[i];
}
for ( int i = 0; i < column.length; i++ ) {
QualifiedName qn = new QualifiedName( column[i] + "_" + table, layerFt.getNameSpace() );
allPt[c++] = FeatureFactory.createSimplePropertyType( qn, types[i], true );
}
QualifiedName qn = new QualifiedName( sourceLayer.getTitle() + "_" + table, layerFt.getNameSpace() );
return FeatureFactory.createFeatureType( qn, false, allPt );
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#getName()
*/
public QualifiedName getName() {
return name;
}
/*
* (non-Javadoc)
*
* @see org.deegree.kernel.Command#getResult()
*/
public Object getResult() {
return resultLayer;
}
}