Skip to content

Commit

Permalink
Integrate GmlTool into deegree3 repository (deegree#1229)
Browse files Browse the repository at this point in the history
* Skip GML reference resolving for WFS-T (deegree#134)

* fix resolving if referenceResolvingMode = CHECK_ALL

* Add documentation for UseExistingSkipResolvingReferences

* #6535 - limitation if occurrence is zero or one

* #6535 - added option to pass reference data

* #6535 - moved content of deegree-cli-utility Tool readme to deegree-webservices-handbook

* #6535 - enhanced documentation

* #6535 - added link to handbook and download link

* #7702 - enhanced documentation of referenceData

* #7692 (PR#158) - access of the transaction in SQLFeatureStore

* #7841 (deegree#1217) - moved module deegree-spring to uncoupled

* #7841 - added GmlTool as new module

* #7841 (deegree#1217) - removed deegree-spring from modules

* #7841 - replaced spring-parent

* #7481 - added reference data

* #7841 - removed deegree-tools-config

* #7841 - removed release pkugin, fixed spring-boot-maven-plugin

* 7841 - fixed instantiation of reference data

* #18 - limit generated mapping to feature types in the refernce data

* #7841 - added jaxb-api dependency

* #18 - limit generated mapping to feature types in the refernce data

* #18 - enhanced documentation

* #7841 - removed duplicated documentation

* #7841 - removed duplicated documentation

* #7841 - fixed jaxb dependencies

* #7841 Remove oracle profile from deegree-tools

Co-authored-by: Lyn Elisa Goltz <goltz@lat-lon.de>
Co-authored-by: tfr42 <torsten.friebe@gmail.com>
  • Loading branch information
3 people authored Dec 1, 2021
1 parent bc72c5f commit 7b2765d
Show file tree
Hide file tree
Showing 72 changed files with 11,129 additions and 633 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,25 @@ public enum IDGenMode {
REPLACE_DUPLICATE,

/** Always generate new ids. */
GENERATE_NEW
GENERATE_NEW;

private boolean skipResolveReferences = false;

/**
* @return <code>true</code> if references should be skipped, <code>false</code> otherwise
*/
public boolean isSkipResolveReferences() {
return skipResolveReferences;
}

/**
* @param skipResolveReferences
* <code>true</code> if references should be skipped, <code>false</code> otherwise
*
* @return the IDGenMode instance
*/
public IDGenMode withSkipResolveReferences( boolean skipResolveReferences ) {
this.skipResolveReferences = skipResolveReferences;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,13 @@ public SQLFeatureStore( SQLFeatureStoreJAXB config, URL configURL, SQLDialect di
}
}

/**
* @return the currently active transaction., may be <code>null</code> if no transaction was acquired
*/
public FeatureStoreTransaction getTransaction() {
return transaction.get();
}

private void initConverters() {
for ( FeatureType ft : schema.getFeatureTypes() ) {
FeatureTypeMapping ftMapping = schema.getFtMapping( ft.getName() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ public void buildInsertRows( final TypedObjectNode particle, final Mapping mappi
Feature feature = (Feature) getPropValue( value );
if ( feature instanceof FeatureReference ) {
FeatureReference featureReference = (FeatureReference) feature;
if ( ( featureReference.isLocal() || featureReference.isResolved() )
if ( !idGenMode.isSkipResolveReferences() && ( featureReference.isLocal() || featureReference.isResolved() )
&& !featureReference.isInternalResolved() ) {
subFeatureRow = lookupFeatureRow( feature.getId() );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,13 @@

import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import static org.apache.xerces.xs.XSComplexTypeDefinition.CONTENTTYPE_ELEMENT;
import static org.apache.xerces.xs.XSComplexTypeDefinition.CONTENTTYPE_EMPTY;
Expand Down Expand Up @@ -132,9 +134,9 @@ public class AppSchemaMapper {

private final int maxComplexityIndex;

private final int allowedCycleDepth;

private final ReferenceData referenceData;

private final int allowedCycleDepth;

/**
* Creates a new {@link AppSchemaMapper} instance for the given schema.
Expand Down Expand Up @@ -184,11 +186,40 @@ public AppSchemaMapper( AppSchema appSchema, boolean createBlobMapping, boolean
public AppSchemaMapper( AppSchema appSchema, boolean createBlobMapping, boolean createRelationalMapping,
GeometryStorageParams geometryParams, int maxLength, boolean usePrefixedSQLIdentifiers,
boolean useIntegerFids, int allowedCycleDepth ) {
this(appSchema, createBlobMapping, createRelationalMapping, geometryParams, maxLength,
usePrefixedSQLIdentifiers, useIntegerFids, allowedCycleDepth, null );
}
/**
* Creates a new {@link AppSchemaMapper} instance for the given schema.
*
* @param appSchema
* application schema to be mapped, must not be <code>null</code>
* @param createBlobMapping
* true, if BLOB mapping should be performed, false otherwise
* @param createRelationalMapping
* true, if relational mapping should be performed, false otherwise
* @param geometryParams
* parameters for storing geometries, must not be <code>null</code>
* @param maxLength
* max length of column names
* @param usePrefixedSQLIdentifiers
* <code>true</code> if the sql identifiers should be prefixed, <code>false</code> otherwise
* @param useIntegerFids
* <code>true</code> if the integer fids should be used, <code>false</code> for uuids
* @param allowedCycleDepth
* depth of the allowed cycles
* @param referenceData
* describing the data stored in the features store
*/
public AppSchemaMapper( AppSchema appSchema, boolean createBlobMapping, boolean createRelationalMapping,
GeometryStorageParams geometryParams, int maxLength, boolean usePrefixedSQLIdentifiers,
boolean useIntegerFids, int allowedCycleDepth, ReferenceData referenceData ) {
this.appSchema = appSchema;
this.geometryParams = geometryParams;
this.useIntegerFids = useIntegerFids;
this.allowedCycleDepth = allowedCycleDepth;
this.maxComplexityIndex = DEFAULT_COMPLEXITY_INDEX * ( allowedCycleDepth + 1 );
this.referenceData = referenceData;

List<FeatureType> ftList = appSchema.getFeatureTypes( null, false, false );
List<FeatureType> blackList = new ArrayList<FeatureType>();
Expand All @@ -207,7 +238,6 @@ public AppSchemaMapper( AppSchema appSchema, boolean createBlobMapping, boolean
Map<String, String> prefixToNs = appSchema.getNamespaceBindings();
GMLSchemaInfoSet xsModel = appSchema.getGMLSchema();

FeatureTypeMapping[] ftMappings = null;

nsToPrefix = new HashMap<String, String>();
Iterator<String> nsIter = CommonNamespaces.getNamespaceContext().getNamespaceURIs();
Expand All @@ -218,6 +248,7 @@ public AppSchemaMapper( AppSchema appSchema, boolean createBlobMapping, boolean
nsToPrefix.putAll( xsModel.getNamespacePrefixes() );

mcManager = new MappingContextManager( nsToPrefix, maxLength, usePrefixedSQLIdentifiers );
FeatureTypeMapping[] ftMappings = null;
if ( createRelationalMapping ) {
ftMappings = generateFtMappings( fts );
}
Expand Down Expand Up @@ -254,15 +285,15 @@ private BBoxTableMapping generateBBoxMapping() {
}

private FeatureTypeMapping[] generateFtMappings( FeatureType[] fts ) {
FeatureTypeMapping[] ftMappings = new FeatureTypeMapping[fts.length];
for ( int i = 0; i < fts.length; i++ ) {
ftMappings[i] = generateFtMapping( fts[i] );
}
return ftMappings;
return Arrays.stream( fts ).filter(
ft -> referenceData != null ?
referenceData.shouldFeatureTypeMapped( ft.getName() ) :
true ).map(
ft -> generateFtMapping( ft ) ).toArray( FeatureTypeMapping[]::new );
}

private FeatureTypeMapping generateFtMapping( FeatureType ft ) {
CycleAnalyser cycleAnalyser = new CycleAnalyser( allowedCycleDepth );
CycleAnalyser cycleAnalyser = new CycleAnalyser( allowedCycleDepth, ft.getName() );
LOG.info( "Mapping feature type '" + ft.getName() + "'" );
MappingContext mc = mcManager.newContext( ft.getName(), detectPrimaryKeyColumnName() );

Expand Down Expand Up @@ -318,7 +349,7 @@ private List<Mapping> generatePropMapping( PropertyType pt, MappingContext mc, C

MappingContext propMc = null;
List<TableJoin> jc = null;
if ( pt.getMaxOccurs() == 1 ) {
if ( pt.getMaxOccurs() == 1 || referenceDataHasOnlyOne( cycleAnalyser ) ) {
propMc = mcManager.mapOneToOneElement( mc, eName );
} else {
propMc = mcManager.mapOneToManyElements( mc, eName );
Expand Down Expand Up @@ -354,7 +385,7 @@ private List<Mapping> generatePropMapping( PropertyType pt, MappingContext mc, C
}

if ( pt instanceof SimplePropertyType ) {
mappings.add( generatePropMapping( (SimplePropertyType) pt, mc ) );
mappings.add( generatePropMapping( (SimplePropertyType) pt, mc, cycleAnalyser ) );
} else if ( pt instanceof GeometryPropertyType ) {
mappings.add( generatePropMapping( (GeometryPropertyType) pt, mc ) );
} else if ( pt instanceof FeaturePropertyType ) {
Expand All @@ -381,13 +412,13 @@ private List<Mapping> generatePropMapping( PropertyType pt, MappingContext mc, C
return mappings;
}

private PrimitiveMapping generatePropMapping( SimplePropertyType pt, MappingContext mc ) {
private PrimitiveMapping generatePropMapping( SimplePropertyType pt, MappingContext mc, CycleAnalyser cycleAnalyser ) {
LOG.debug( "Mapping simple property '" + pt.getName() + "'" );
ValueReference path = getPropName( pt.getName() );
MappingContext propMc = null;
List<TableJoin> jc = null;
MappingExpression mapping = null;
if ( pt.getMaxOccurs() == 1 ) {
if ( pt.getMaxOccurs() == 1 || referenceDataHasOnlyOne( cycleAnalyser ) ) {
propMc = mcManager.mapOneToOneElement( mc, pt.getName() );
mapping = new DBField( propMc.getColumn() );
} else {
Expand Down Expand Up @@ -468,7 +499,7 @@ private CompoundMapping generatePropMapping( CustomPropertyType pt, MappingConte

MappingContext propMc = null;
List<TableJoin> jc = null;
if ( pt.getMaxOccurs() == 1 ) {
if ( pt.getMaxOccurs() == 1 || referenceDataHasOnlyOne( cycleAnalyser ) ) {
propMc = mcManager.mapOneToOneElement( mc, pt.getName() );
} else {
propMc = mcManager.mapOneToManyElements( mc, pt.getName() );
Expand Down Expand Up @@ -714,6 +745,8 @@ private List<Mapping> generateMapping( XSTerm term, int occurence, MappingContex
private List<Mapping> generateMapping( XSElementDeclaration elDecl, int occurence, MappingContext mc,
CycleAnalyser cycleAnalyser ) {
cycleAnalyser.add( elDecl );
if ( referenceDataHasOnlyOne( cycleAnalyser ) )
occurence = 1;

List<Mapping> mappings = new ArrayList<Mapping>();

Expand Down Expand Up @@ -818,6 +851,14 @@ private List<Mapping> generateMapping( XSWildcard wildCard, int occurrence, Mapp
return new ArrayList<>();
}

private boolean referenceDataHasOnlyOne( CycleAnalyser cycleAnalyser ) {
if ( referenceData == null )
return false;
List<QName> xpath = cycleAnalyser.getPath();
QName featureTypeName = cycleAnalyser.getFeatureTypeName();
return referenceData.hasZeroOrOneProperty( featureTypeName, xpath );
}

private String getName( QName name ) {
if ( name.getNamespaceURI() != null && !name.getNamespaceURI().equals( "" ) ) {
String prefix = nsToPrefix.get( name.getNamespaceURI() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ public class CycleAnalyser {

private final int allowedCycleDepth;

private final QName featureTypeName;

/**
* @param allowedCycleDepth
* the allowed depth of cycles
* @param featureTypeName name of the feature type, never <code>null</code>
*/
CycleAnalyser( int allowedCycleDepth ) {
CycleAnalyser( int allowedCycleDepth, QName featureTypeName ) {
this.allowedCycleDepth = allowedCycleDepth;
this.featureTypeName = featureTypeName;
}

/**
Expand Down Expand Up @@ -141,6 +145,20 @@ public List<XSElementDeclaration> getElementDeclarations() {
return parentEls;
}

/**
* @return the name of the feature type, never <code>null</code>
*/
public QName getFeatureTypeName() {
return featureTypeName;
}

/**
* @return the current path. May be empty but never <code>null</code>
*/
public List<QName> getPath() {
return path;
}

private void log() {
StringBuffer sb = new StringBuffer();
Map<QName, Integer> nameToCycleDepth = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.deegree.feature.persistence.sql.mapper;

import org.deegree.commons.tom.ElementNode;
import org.deegree.commons.tom.TypedObjectNode;
import org.deegree.commons.tom.gml.property.Property;
import org.deegree.cs.exceptions.UnknownCRSException;
import org.deegree.feature.Feature;
import org.deegree.feature.FeatureCollection;
import org.deegree.feature.types.FeatureType;
import org.deegree.gml.GMLInputFactory;
import org.deegree.gml.GMLStreamReader;
import org.deegree.gml.GMLVersion;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a>
*/
public class GmlReferenceData implements ReferenceData {

private Map<QName, List<Feature>> features;

public GmlReferenceData( URL referenceData )
throws IOException, XMLStreamException, UnknownCRSException {
GMLStreamReader gmlStreamReader = GMLInputFactory.createGMLStreamReader( GMLVersion.GML_32, referenceData );
FeatureCollection featureCollection = gmlStreamReader.readFeatureCollection();
this.features = featureCollection.stream().collect( Collectors.groupingBy( Feature::getName ) );
}

@Override
public boolean hasZeroOrOneProperty( QName featureTypeName, List<QName> xpath ) {
List<Feature> featuresOfType = this.features.get( featureTypeName );
if ( featuresOfType != null && !featuresOfType.isEmpty() ) {
for ( Feature feature : featuresOfType ) {
if ( hasMoreThanOne( feature, xpath ) )
return false;
}
return true;
}
return false;
}

@Override
public boolean shouldFeatureTypeMapped( QName featureTypeName ) {
return features.containsKey( featureTypeName );
}

private boolean hasMoreThanOne( Feature feature, List<QName> xpath ) {
if ( xpath.isEmpty() )
return true;
Iterator<QName> iterator = xpath.iterator();
QName firstProperty = iterator.next();
List<Property> properties = feature.getProperties( firstProperty );
return hasMoreThanOne( iterator, properties );
}

private <T extends ElementNode> boolean hasMoreThanOne( Iterator<QName> iterator, List<T> properties ) {
if ( !iterator.hasNext() ) {
if ( properties.size() > 1 )
return true;
else
return false;
} else {
QName next = iterator.next();
for ( ElementNode property : properties ) {
List<ElementNode> subProperties = getChildsByName( property, next );
if ( hasMoreThanOne( iterator, subProperties ) )
return true;
}
return false;
}
}

private List<ElementNode> getChildsByName( ElementNode property, QName propertyName ) {
List<ElementNode> properties = new ArrayList<>();
List<TypedObjectNode> children = property.getChildren();
for ( TypedObjectNode child : children ) {
if ( child instanceof ElementNode ) {
QName name = ( (ElementNode) child ).getName();
if ( name.equals( propertyName ) )
properties.add( (ElementNode) child );
}
}
return properties;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.deegree.feature.persistence.sql.mapper;

import javax.xml.namespace.QName;
import java.util.List;

/**
* @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz </a>
*/
public interface ReferenceData {

/**
* @param featureTypeName
* the name of the feature type, never <code>null</code>
* @param xpath
* the steps describing the path to the feature, may be empty. but never <code>null</code>
* @return <code>true</code> if the property identified by the path occurs one or zero times, <code>false</code> otherwise
*/
boolean hasZeroOrOneProperty( QName featureTypeName, List<QName> xpath );

/**
* @param featureTypeName
* the name of the feature type, never <code>null</code>
* @return <code>true</code> if the feature type with this name should be mapped, <code>false</code> otherwise
*/
boolean shouldFeatureTypeMapped( QName featureTypeName );

}
Loading

0 comments on commit 7b2765d

Please sign in to comment.