/**
* Copyright (C) 2008 - 2014 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* - Apache License, version 2.0
* - Apache Software License, version 1.0
* - GNU Lesser General Public License, version 3
* - Mozilla Public License, versions 1.0, 1.1 and 2.0
* - Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public
* icense version 2 and the aforementioned licenses.
*
* 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.
*/
package org.n52.ses.services.enrichment;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import net.opengis.wfs.x20.MemberPropertyType;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.n52.oxf.conversion.gml32.geometry.GeometryWithInterpolation;
import org.n52.oxf.conversion.gml32.xmlbeans.jts.GMLGeometryFactory;
import org.n52.ses.api.event.MapEvent;
import org.n52.ses.io.parser.OWS8Parser;
import org.n52.ses.io.parser.aixm.ElevatedSurfaceGeometry;
import org.n52.ses.io.parser.aixm.jts.AIXMGeometryFactory;
import org.n52.ses.services.wfs.WFSConnector;
import org.n52.ses.services.wfs.WFSQuery;
import org.n52.ses.services.wfs.queries.GetAssociatedFeatureByGMLIdentifier;
import org.n52.ses.services.wfs.queries.GetFeatureByAIXMDesignator;
import org.n52.ses.services.wfs.queries.GetFeatureByGMLIdentifier;
import org.n52.ses.util.common.ConfigurationRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import aero.aixm.schema.x51.AirportHeliportType;
import aero.aixm.schema.x51.AirspaceType;
import aero.aixm.schema.x51.ApronElementType;
import aero.aixm.schema.x51.RunwayElementType;
import aero.aixm.schema.x51.TaxiwayElementType;
import com.vividsolutions.jts.geom.Geometry;
public class WFSHandler implements EnrichmentHandler {
private List<WFSConnector> wfsInstances;
private static final Logger logger = LoggerFactory.getLogger(WFSHandler.class);
public WFSHandler() {
wfsInstances = new ArrayList<WFSConnector>();
initWFSConnectors(ConfigurationRegistry.getInstance().getPropertyForKey("WFS_URL"));
}
/**
* Reads the configuration for WFS-settings and
* initializes for each WFS an WFS-Connector.
*
* @param propertyForKey
* the property-string for the WFSs
*/
private void initWFSConnectors(String propertyForKey){
if (propertyForKey == null) return;
// get properties of each WFS
String[] wfsKeys = propertyForKey.split(";");
for (String s : wfsKeys){
WFSConnector wfsC = null;
StringTokenizer st = new StringTokenizer(s,"@@");
// url
String url = st.nextToken();
// soap
String soapString = st.nextToken();
Boolean usesSOAP = false;
if (soapString.equals("true"))
usesSOAP = true;
// authentication
String auth = "";
if (st.hasMoreTokens())
auth = st.nextToken().trim();
// get user name and pw if available, create WFSConnector
if (!auth.isEmpty()){
String[] accessArray = auth.split(":");
Map<String,String> userPW = new HashMap<String,String>();
userPW.put(WFSConnector.USER_KEY, accessArray[0]);
userPW.put(WFSConnector.PASSWORD_KEY, accessArray[1]);
wfsC = new WFSConnector(url, usesSOAP, userPW);
} else{
wfsC = new WFSConnector(url, usesSOAP);
}
// add WFS to list
if (wfsC != null)
wfsInstances.add(wfsC);
}
}
@Override
public boolean enrichFeature(MapEvent mapEvent, String identifier,
String featureType) {
if (mapEvent.containsKey(MapEvent.GEOMETRY_KEY)) return false;
// set parameter list for WFC connectors
HashMap<String,String> featureOpts = new HashMap<String, String>();
featureOpts.put(WFSConnector.FEATURE_TYPE_KEY, featureType);
if (identifier != null)
featureOpts.put(WFSConnector.GML_IDENTIFIER_KEY, identifier);
if (identifier == null || featureType == null) {
return false;
}
// enrich a specific feature type
Geometry bbox = null;
try {
XmlObject[] wfsFeatures = executeQuery(createGetFeatureQuery(featureOpts));
if (wfsFeatures != null) {
bbox = resolveGeometry(wfsFeatures);
}
} catch (Exception e) {
logger.info("Could not enrich event, identifier: " + identifier);
logger.warn(e.getMessage(), e);
}
// enrichment: add information to mapEvent
if (bbox != null) {
logger.info("ENRICHMENT of event, adding geometry");
mapEvent.put(MapEvent.GEOMETRY_KEY, bbox);
return true;
}
return false;
}
private Geometry resolveGeometry(XmlObject[] wfsFeatures) throws Exception {
for (XmlObject xmlObject : wfsFeatures) {
MemberPropertyType member;
if (xmlObject instanceof MemberPropertyType) {
member = (MemberPropertyType) xmlObject;
XmlCursor cur = member.newCursor();
cur.toFirstChild();
XmlObject inner = cur.getObject();
// calculate a bounding box from WFS-response for the specific feature type
if (inner instanceof AirportHeliportType){
return enrichWithAirportHeliport((AirportHeliportType) inner);
}
else if (inner instanceof AirspaceType){
return enrichWithAirspace((AirspaceType) inner);
}
else if (inner instanceof RunwayElementType){
return enrichWithRunway((RunwayElementType) inner);
}
else if (inner instanceof TaxiwayElementType) {
return enrichWithTaxiway((TaxiwayElementType) inner);
}
else if (inner instanceof ApronElementType) {
return enrichWithApron((ApronElementType) inner);
}
}
}
return null;
}
private WFSQuery createGetFeatureQuery(HashMap<String, String> featureOpts) {
if (!featureOpts.containsKey(WFSConnector.FEATURE_TYPE_KEY)) {
throw new IllegalStateException("No FeatureType defined for the WFS Query.");
}
String featureType = featureOpts.get(WFSConnector.FEATURE_TYPE_KEY);
if (featureType.equals(OWS8Parser.AIXM_RUNWAY_KEY) || featureType.equals(OWS8Parser.AIXM_TAXIWAY_KEY) ||
featureType.equals(OWS8Parser.AIXM_APRON_KEY)){
return new GetAssociatedFeatureByGMLIdentifier(featureOpts.get(WFSConnector.FEATURE_TYPE_KEY), 10,
featureOpts.get(WFSConnector.GML_IDENTIFIER_KEY));
}
if (featureOpts.containsKey(WFSConnector.DESIGNATOR_KEY)) {
return new GetFeatureByAIXMDesignator(featureOpts.get(WFSConnector.FEATURE_TYPE_KEY), 10,
featureOpts.get(WFSConnector.DESIGNATOR_KEY));
}
else if (featureOpts.containsKey(WFSConnector.GML_IDENTIFIER_KEY)) {
return new GetFeatureByGMLIdentifier(featureOpts.get(WFSConnector.FEATURE_TYPE_KEY), 10,
featureOpts.get(WFSConnector.GML_IDENTIFIER_KEY));
}
return null;
}
/**
* Calculates the bounding box from the members in the WFS-response.
*
* @param inner
* features from the wfs
* @return {@link Geometry}
* the bounding box
* @throws Exception
*/
private Geometry enrichWithTaxiway(TaxiwayElementType inner) throws Exception {
ElevatedSurfaceGeometry geom = AIXMGeometryFactory.resolveTaxiwayElementGeometry(inner, new Date());
if (geom == null) return null;
GeometryWithInterpolation withInterpol = geom.getGeometries().iterator().next();
GMLGeometryFactory.checkAndApplyInterpolation(withInterpol);
return withInterpol.getGeometry();
}
/**
* Calculates the bounding box from the members in the WFS-response.
*
* @param inner
* features from the wfs
* @return {@link Geometry}
* the bounding box
* @throws Exception
*/
private Geometry enrichWithRunway(RunwayElementType inner) throws Exception {
ElevatedSurfaceGeometry geom = AIXMGeometryFactory.resolveRunwayElementGeometry(inner, new Date());
if (geom == null) return null;
GeometryWithInterpolation withInterpol = geom.getGeometries().iterator().next();
GMLGeometryFactory.checkAndApplyInterpolation(withInterpol);
return withInterpol.getGeometry();
}
private Geometry enrichWithApron(ApronElementType inner) throws Exception {
ElevatedSurfaceGeometry geom = AIXMGeometryFactory.resolveApronElementGeometry(inner, new Date());
if (geom == null) return null;
GeometryWithInterpolation withInterpol = geom.getGeometries().iterator().next();
GMLGeometryFactory.checkAndApplyInterpolation(withInterpol);
return withInterpol.getGeometry();
}
/**
* Calculates the bounding box from the members in the WFS-response.
*
* @param aerodromes
* features from the wfs
* @return {@link Geometry}
* the bounding box
* @throws Exception
*/
private Geometry enrichWithAirportHeliport(AirportHeliportType ah) throws Exception{
if (ah != null){
GeometryWithInterpolation result = AIXMGeometryFactory.resolveAirportHeliportGeometry(ah, new Date());
return result.getGeometry();
}
return null;
}
/**
* Calculates the bounding box from the members in the WFS-response.
*
* @param inner
* features from the wfs
* @return {@link Geometry}
* the bounding box
* @throws Exception
*/
private Geometry enrichWithAirspace(AirspaceType inner) throws Exception{
Geometry boundingBox = null;
return boundingBox;
}
public XmlObject[] executeQuery(WFSQuery query) {
for (WFSConnector wfsC : wfsInstances){
XmlObject[] wfsFeatures;
try {
wfsFeatures = wfsC.executeQuery(query);
} catch (Exception e) {
logger.warn(wfsC.getURL() + "; " +e.getMessage());
continue;
}
if (wfsFeatures != null)
return wfsFeatures;
}
return null;
}
@Override
public boolean canHandle(String featureType) {
if (featureType.equals(OWS8Parser.AIXM_AIRPORT_HELIPORT_KEY)){
return true;
}
else if (featureType.equals(OWS8Parser.AIXM_AIRSPACE_KEY)){
return true;
}
else if (featureType.equals(OWS8Parser.AIXM_RUNWAY_KEY)){
return true;
}
else if (featureType.equals(OWS8Parser.AIXM_TAXIWAY_KEY)){
return true;
}
else if (featureType.equals(OWS8Parser.AIXM_NAVAID_KEY)) {
return true;
}
return false;
}
}