/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package de.cismet.cismap.commons.featureservice; import org.deegree.ogcwebservices.wfs.capabilities.FeatureTypeList; import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilities; import org.deegree.ogcwebservices.wfs.capabilities.WFSCapabilitiesDocument; import org.deegree.ogcwebservices.wfs.capabilities.WFSFeatureType; import org.jdom.Document; import org.jdom.Element; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.net.URL; import java.nio.charset.Charset; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Vector; import de.cismet.commons.security.AccessHandler.ACCESS_METHODS; import de.cismet.security.WebAccessManager; import de.cismet.tools.StaticHtmlTools; /** * DOCUMENT ME! * * @author nh * @version $Revision$, $Date$ * @deprecated This class should not be used, because the methods do not consider the request version, when they change * queries. */ public class WFSOperator { //~ Static fields/initializers --------------------------------------------- /** Log4J Initialisierung. */ private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger( "de.cismet.cismap.commons.raster.wfs.WFSQueryFactory"); // NOI18N public static final String CISMAP_QUERY = "CismapQuery"; // NOI18N public static final String QUERY = "Query"; // NOI18N public static final String CISMAP_DESCRIBEFEATURETYPE = "CismapDescribeFeatureType"; // NOI18N public static final String DESCRIBEFEATURETYPE = "DescribeFeatureType"; // NOI18N public static final String CISMAP_GETCAPABILITIES = "CismapGetCapabilities"; // NOI18N public static final String GETCAPABILITIES = "GetCapabilities"; // NOI18N public static final String SERVICE_IDENT = "ServiceIdentification"; // NOI18N public static final String FILTER = "Filter"; // NOI18N public static final String BBOX = "BBOX"; // NOI18N public static final String GET_FEATURE = "GetFeature"; // NOI18N public static final String TYPE_NAME = "typeName"; // NOI18N public static final String DFT_TYPE_NAME = "TypeName"; // NOI18N public static final String PROPERTY_NAME = "PropertyName"; // NOI18N public static final String GEO_PROPERTY_TYPE = "gml:GeometryPropertyType"; // NOI18N /** WFS-Namespace-Konstante. */ public static final Namespace WFS = Namespace.getNamespace("wfs", "http://www.opengis.net/wfs"); // NOI18N /** OGC-Namespace-Konstante. */ public static final Namespace OGC = Namespace.getNamespace("ogc", "http://www.opengis.net/ogc"); // NOI18N /** GML-Namespace-Konstante. */ public static final Namespace GML = Namespace.getNamespace("gml", "http://www.opengis.net/gml"); // NOI18N /** OWS-Namespace-Konstante. */ public static final Namespace OWS = Namespace.getNamespace("ows", "http://www.opengis.net/ows"); // NOI18N /** XSD-Namespace-Konstante. */ public static final Namespace xsd = Namespace.getNamespace("xsd", "http://www.w3.org/2001/XMLSchema"); // NOI18N //~ Instance fields -------------------------------------------------------- private final URL XML_FILE = getClass().getResource("wfs.xml"); // NOI18N private Document xmlDoc; private Document capabilities; private Element rootNode; private Element query; //~ Constructors ----------------------------------------------------------- /** * Standardkonstruktor. Erstellt die XML-Datei mit WFS-Abfragen. */ public WFSOperator() { if (log.isDebugEnabled()) { log.debug("createStandardQuery()"); // NOI18N } try { final SAXBuilder builder = new SAXBuilder(); xmlDoc = builder.build(XML_FILE); rootNode = xmlDoc.getRootElement(); } catch (Exception ex) { log.error("Error during parsing of the CismapXML-Files", ex); // NOI18N } } /** * Konstruktor f\u00FCr WFSQueryFactory-Objekte. * * @param typeName der Typname des abzufragenden Features */ public WFSOperator(final String typeName) { if (log.isDebugEnabled()) { log.debug("createStandardQuery(" + typeName + ")"); // NOI18N } try { final SAXBuilder builder = new SAXBuilder(); xmlDoc = builder.build(XML_FILE); rootNode = xmlDoc.getRootElement(); query = rootNode.getChild(CISMAP_QUERY).getChild(GET_FEATURE, WFS); query.getChild(QUERY, WFS).getAttribute(TYPE_NAME).setValue(typeName); } catch (Exception ex) { log.error("Error during the creation of a default query.", ex); // NOI18N } } //~ Methods ---------------------------------------------------------------- /** * Setzt abzufragende Properties. * * @param properties Element-Collection mit PropertyNames */ public void setPropertyNames(final Collection<Element> properties) { getQuery().getChild(QUERY, WFS).removeChildren(PROPERTY_NAME, WFS); for (final Element e : properties) { final Element tmp = new Element(PROPERTY_NAME, WFS); tmp.setText(e.getAttributeValue("name")); // NOI18N getQuery().getChild(QUERY, WFS).addContent(tmp); } } /** * Durchsucht das übergebene WFSQuery nach vorhandenen Attributen (PropertyNames) und liefert diese als * String-Vector zurück. * * @param query zu durchsuchendes Query * * @return Vector<String> mit gefundenen Attributen */ public static Vector<String> getPropertyNamesFromQuery(final Element query) { final Vector<String> result = new Vector<String>(); try { for (final Object o : query.getChild(QUERY, WFS).getChildren(PROPERTY_NAME, WFS)) { if (o instanceof Element) { result.add(((Element)o).getText()); } } if (log.isDebugEnabled()) { log.debug(result); } } catch (Exception ex) { log.error("Error in getPropertyNamesFromQuery()"); // NOI18N return new Vector(); } return result; } /** * Ersetzt die bisher in der Query vorhandenen Properties durch die der übergebenen String-Collection. * * @param query WFSQuery als JDOM-Element * @param properties String-Collection mit PropertyNames * * @return DOCUMENT ME! */ public static Element changePropertyNames(final Element query, final Collection<String> properties) { query.getChild(QUERY, WFS).removeChildren(PROPERTY_NAME, WFS); for (final String s : properties) { final Element tmp = new Element(PROPERTY_NAME, WFS); tmp.setText(s); query.getChild(QUERY, WFS).addContent(tmp); } return query; } /** * Setzt den Geometrie-Namen. * * @param e geo Element mit dem Geometrie-Namen */ public void setGeometry(final Element e) { for (final Element tmp : (List<Element>)e.getChildren()) { if (tmp.getAttributeValue("type").equals(GEO_PROPERTY_TYPE)) { // NOI18N getQuery().getChild(QUERY, WFS) .getChild(FILTER, OGC) .getChild(BBOX, OGC) .getChild(PROPERTY_NAME, OGC) .setText(tmp.getAttributeValue("name")); // NOI18N break; } } } /** * Setzt den Geometrie-Namen. * * @param query WFSQuery als JDOM-Element * @param s String mit dem Geometrie-Namen */ public static void setGeometry(final Element query, final String s) { query.getChild(QUERY, WFS).getChild(FILTER, OGC).getChild(BBOX, OGC).getChild(PROPERTY_NAME, OGC).setText(s); } /** * Liefert den im Query-Element gesetzten Geometrienamen. * * @param query WFSQuery als JDOM-Element * * @return String mit dem Geometrie-Namen */ public static String getGeometry(final Element query) { return query.getChild(QUERY, WFS) .getChild(FILTER, OGC) .getChild(BBOX, OGC) .getChild(PROPERTY_NAME, OGC) .getTextTrim(); } /** * Liefert einen String aus einem JDOM-Element mittels XMLOutputter. * * @param e JDOM-Element * * @return XML, das das JDOM-Element repr\u00E4sentiert */ public static String elementToString(final Element e) { if (e == null) { return ""; // NOI18N } else { final XMLOutputter out = new XMLOutputter(Format.getPrettyFormat()); return out.outputString(e); } } /** * Liefert das fertige GetFeature-Query. * * @return Query als JDOM-Element */ public Element getQuery() { return query; } /** * Erzeugt einen String der einen DescribeFeatureType-Request in XML repr\u00E4sentiert. * * @param name der Name des Features das beschrieben werden soll * * @return DescribeFeatureType-Request als String */ public String createDescribeFeatureTypeRequest(final String name) { if (log.isDebugEnabled()) { log.debug("Create DescribeFeatureTypeRequest for " + name); // NOI18N } final Element describeFeatType = rootNode.getChild(CISMAP_DESCRIBEFEATURETYPE) .getChild(DESCRIBEFEATURETYPE, WFS); describeFeatType.getChild(DFT_TYPE_NAME, WFS).setText(name); return elementToString(describeFeatType); } /** * Erzeugt einen String der einen GetCapabilities-Request in XML repr\u00E4sentiert. * * @return GetCapabilities-Request als String */ private String createGetCapabilitiesRequest() { if (log.isDebugEnabled()) { log.debug("Create GetCapabilitiesRequest"); // NOI18N } return elementToString(rootNode.getChild(CISMAP_GETCAPABILITIES).getChild(GETCAPABILITIES, WFS)); } /** * Erstellt ein WFSCapabilities-Objekt per HTTP-POST-Request. * * @param server URL des WFS-Servers * * @return WFSCapabilities-Objekt * * @throws Exception DOCUMENT ME! */ public WFSCapabilities parseWFSCapabilites(final URL server) throws Exception { final XMLOutputter out = new XMLOutputter(); capabilities = doRequest(server, createGetCapabilitiesRequest()); final String buf = out.outputString(capabilities); final WFSCapabilitiesDocument wfsDoc = new WFSCapabilitiesDocument(); wfsDoc.load(new StringReader(buf), "http://test0r"); // NOI18N return (WFSCapabilities)wfsDoc.parseCapabilities(); } /** * DOCUMENT ME! * * @param reader DOCUMENT ME! * * @return DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ public WFSCapabilities parseWFSCapabilites(final BufferedReader reader) throws Exception { final WFSCapabilitiesDocument wfsDoc = new WFSCapabilitiesDocument(); wfsDoc.load(reader, "http://test0r"); // NOI18N return (WFSCapabilities)wfsDoc.parseCapabilities(); } /** * Liefert, falls in den Capabilities vorhanden, einen Namen f\u00FCr den WFS oder einen Standardnamen. * * @return Name des WFS oder "WFS", falls keiner gefunden */ public String getServiceName() { final Element id = capabilities.getRootElement().getChild(SERVICE_IDENT, OWS); if ((id.getChild("Title", OWS) != null) && !id.getChild("Title", OWS).getText().equals("")) { // NOI18N return id.getChild("Title", OWS).getText(); // NOI18N } else if ((id.getChild("Abstract", OWS) != null) && !id.getChild("Abstract", OWS).getText().equals("")) { // NOI18N return id.getChild("Abstract", OWS).getText(); // NOI18N } else { return id.getChild("ServiceType", OWS).getText(); // NOI18N } } /** * Erzeugt aus einem JDOM-Document einen String. * * @param doc JDOM-Document * * @return das JDOM-Documents als String */ public static String parseDocumentToString(final Document doc) { if (log.isDebugEnabled()) { log.debug("parseDocumentToString()"); // NOI18N } final XMLOutputter out = new XMLOutputter(); return out.outputString(doc); } /** * Erstellt aus der ServerURL und der FeatureTypeList eine Liste mit allen FeatureTypen und deren Parametern aus * JDOM-Elementen. * * @param postURL URL des WFS-Servers * @param featTypes FeatureTypeList der WFSCapabilties * * @return Liste mit allen zum Namen gefundenen Attributen * * @throws Exception DOCUMENT ME! */ public List<Element> getElements(final URL postURL, final FeatureTypeList featTypes) throws Exception { if (log.isDebugEnabled()) { log.debug("getElements()"); // NOI18N } Document doc = null; // Ergebnisliste erstellen final List<Element> list = new LinkedList<Element>(); // Hole Elemente + Parameter f\u00FCr alle FeatureTypes for (int i = 0; i < featTypes.getFeatureTypes().length; i++) { final WFSFeatureType ft = featTypes.getFeatureTypes()[i]; final String name = ft.getName().getAsString(); Element element = null; // Wenn noch keine Abfrage gemacht wurde, hole DescribeFeatureType if (doc == null) { doc = doRequest(postURL, createDescribeFeatureTypeRequest(name)); } // Versuche im bestehenden Document das Element zu finden element = getAttributes(name, doc); // Wenn es nicht gefunden wurde, hole ein neues Document per DescribeFeatureType if (element == null) { doc = doRequest(postURL, createDescribeFeatureTypeRequest(name)); element = getAttributes(name, doc); } if (checkElementHasGeometry(element)) { list.add(element); } } return list; } /** * Testet das Element, ob es einen Geometrietyp besitzt. Besitzt es keinen, so ist es auch f\u00FCr die Anzeige als * FeatureLayer uninteressant. * * @param element das zu pr\u00FCfende Element * * @return true wenn Geometrietyp gefunden, sonst false */ private boolean checkElementHasGeometry(final Element element) { for (final Element e : (List<Element>)element.getChildren()) { if (e.getAttributeValue("type").equals(GEO_PROPERTY_TYPE)) { // NOI18N return true; } } return false; } /** * Versucht im gegebenen JDOM-Document das Element mit dem Namen zu finden. * * @param name gesuchter Elementname * @param doc JDOM-Document mit XML-Informationen * * @return Element-Objekt falls gefunden, sonst null */ private static Element getAttributes(final String name, final Document doc) { // Gefundenes Element zur Zur\u00FCckgabe Element result = null; final String shortName = deleteApp(name); String type = null; try { for (final Object o : doc.getContent()) { if (o instanceof Element) { final Element root = (Element)o; String prefix = null; // Iteriere \u00FCber alle Element-Objekte die Kinder des Roots sind for (final Object child : root.getChildren("element", xsd)) { // NOI18N final Element e = (Element)child; // Pr\u00FCfe jedes Kind des Root-Knotens, ob der Name \u00FCbereinstimmt if ((e.getAttributeValue("name") != null) && e.getAttributeValue("name").equals(shortName)) { // NOI18N if (log.isDebugEnabled()) { // Wenn ja, dann speichere ihn tempor\u00E4r und springe aus der Schleife log.debug(">> Element with name = \"" + name + "\" found"); // NOI18N } e.setAttribute("name", name); // NOI18N result = e; prefix = e.getAttributeValue("type") .substring(0, e.getAttributeValue("type").indexOf(":") + 1); // NOI18N type = deleteApp(e.getAttributeValue("type")); // NOI18N if (log.isDebugEnabled()) { log.debug(">> searched Typ = \"" + e.getAttributeValue("type") + "\""); // NOI18N } break; } } // Iteriere \u00FCber alle complexType-Elemente die Kinder des Roots sind for (final Object child : ((Element)root).getChildren("complexType", xsd)) { // NOI18N final Element comp = (Element)child; // Pr\u00FCfe, ob der Name des complexType mit dem gesuchten Typ \u00FCbereinstimmt if (comp.getAttributeValue("name").equals(type)) { // NOI18N // Wenn ja, dann gib die Attribute des complexTypes zur\u00FCck final List l = comp.getChild("complexContent", xsd) .getChild("extension", xsd) .getChild("sequence", xsd) .getChildren("element", xsd); // NOI18N while (l.size() > 0) { final Element neu = (Element)((Element)l.get(0)).detach(); neu.setAttribute("name", prefix + neu.getAttributeValue("name")); // NOI18N result.addContent(neu); } if (log.isDebugEnabled()) { log.debug("OK, result = " + result); // NOI18N } return result; } } } } } catch (Exception ex) { log.error("Error at getElements()", ex); // NOI18N } return null; } /** * L\u00F6scht das erste Auftreten von "app:" aus einem String. * * @param s der zu bearbeitende String * * @return String ohne "app:" */ public static String deleteApp(final String s) { if (s.startsWith("app:")) { // NOI18N return s.replaceAll("app:", ""); // NOI18N } else { return s; } } /** * Stellt einen POST-Request an die Server-URL und gibt einen InputStream zur\u00FCck aus dem die Antwort des * Servers ausgelesen werden kann. * * @param serverURL URL des anzusprechenden Servers * @param request Request-String * * @return Serverantwort als InputStream * * @throws Exception DOCUMENT ME! */ public static Document doRequest(final URL serverURL, final String request) throws Exception { // log.info("HTTPCommunicator.doRequest()"); // // HTTP-Client erstellen // HttpClient client = new HttpClient(); // // // Hole den Status, ob momentan ein Proxy gesetzt ist // String proxySet = System.getProperty("proxySet"); // // // Proxy vorhanden ... // if (proxySet != null && proxySet.equals("true")) { // log.debug("Proxy vorhanden"); // log.debug("ProxyHost:" + System.getProperty("http.proxyHost")); // log.debug("ProxyPort:" + System.getProperty("http.proxyPort")); // try { // // F\u00FCge den vorhandenen Proxy dem HTTP-Client hinzu // client.getHostConfiguration().setProxy(System.getProperty("http.proxyHost"), // Integer.parseInt(System.getProperty("http.proxyPort"))); // } catch (Exception ex) { // log.error("Proxy im HTTP-Client setzen fehlgeschlagen", ex); // } // // } else { // sonst tue nichts // log.debug("kein Proxy"); // } // // // Erstelle neue POST-Methode mit der Server-URL // PostMethod httppost = new PostMethod(serverURL.toString()); // log.debug("ServerURL = " + httppost.getURI().toString()); // // // Requeststring speichern, damit das Original nicht ver\u00E4ndert wird. final String poststring = request; if (log.isDebugEnabled()) { // // // Erstelle HTML aus dem Request und \u00E4ndere sein Charset auf ISO log.debug("WFS Query = " + StaticHtmlTools.stringToHTMLString(poststring)); // NOI18N } // String modifiedString = new String(poststring.getBytes("UTF-8"), "ISO-8859-1"); // httppost.setRequestEntity(new StringRequestEntity(modifiedString)); try { // POST-Methode an den Server schicken // client.executeMethod(httppost); final InputStream result = WebAccessManager.getInstance() .doRequest(serverURL, new StringReader(poststring), ACCESS_METHODS.POST_REQUEST); if (log.isDebugEnabled()) { // Falls Antwort == OK // if (httppost.getStatusCode() == HttpStatus.SC_OK) { log.debug("Server has processed request and responds"); // NOI18N log.debug("parse InputStream"); // NOI18N } final SAXBuilder builder = new SAXBuilder(); return builder.build(new InputStreamReader(result, Charset.forName("UTF-8"))); // NOI18N // } else { // log.error("Unexpected failure: " + httppost.getStatusLine().toString()); // } } catch (Exception ex) { log.error(ex); } return null; } }