From c430e66e5cc1e60ceea293a23fc73c3d192be15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20M=C3=A9liani?= <m.meliani@neogeo-online.net> Date: Wed, 9 Oct 2013 16:48:06 +0200 Subject: [PATCH] Deleted mapfile.py --- src/mapfile.py | 1071 ------------------------------------------------ src/server.py | 1 - src/tools.py | 1 - 3 files changed, 1073 deletions(-) delete mode 100644 src/mapfile.py diff --git a/src/mapfile.py b/src/mapfile.py deleted file mode 100644 index 2166ad2..0000000 --- a/src/mapfile.py +++ /dev/null @@ -1,1071 +0,0 @@ -#!/usr/bin/env python2.7 -# -*- coding: utf-8 -*- - -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# # -# MapServer REST API is a python wrapper around MapServer which # -# allows to manipulate a mapfile in a RESTFul way. It has been # -# developped to match as close as possible the way the GeoServer # -# REST API acts. # -# # -# Copyright (C) 2011-2013 Neogeo Technologies. # -# # -# This file is part of MapServer Rest API. # -# # -# MapServer Rest API is free software: you can redistribute it # -# and/or modify it under the terms of the GNU General Public License # -# as published by the Free Software Foundation, either version 3 of # -# the License, or (at your option) any later version. # -# # -# MapServer Rest API 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. # -# # -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - -import os -import re -import mapscript -import urlparse -import stores -import metadata -import webapp - -import functools - -from webapp import KeyExists - -import tools -from extensions import plugins - -class MetadataMixin(object): - - def __getattr__(self, attr): - if hasattr(self, "ms") and hasattr(metadata, attr): - return functools.partial(getattr(metadata, attr), self.ms) - raise AttributeError("'%s' object has no attribute '%s'" % - (type(self).__name__, attr)) - - -def get_store_connection_string(info): - cparam = info["connectionParameters"] - if cparam.get("dbtype", "") == "postgis": - # First mandatory - url = "PG:dbname=%s port=%s host=%s " % (cparam["database"], cparam["port"], cparam["host"]) - # Then optionals: - url += " ".join("%s=%s" % (p, cparam[p]) for p in ["user", "password"] if p in cparam) - return url - elif "url" in cparam: - url = urlparse.urlparse(cparam["url"]) - if url.scheme != "file" or url.netloc: - raise ValueError("Only local files are suported.") - return tools.get_resource_path(url.path) - else: - raise ValueError("Unhandled type '%s'" % cparam.get("dbtype", "<unknown>")) - - -class Class(object): - """ - """ - - def __init__(self, backend): - self.ms = backend - - -class Layer(MetadataMixin): - """ - """ - - def __init__(self, backend): - self.ms = backend - - def enable(self, enabled=True): - requests = ["GetCapabilities", "GetMap", "GetFeatureInfo", "GetLegendGraphic"] - self.ms.status = mapscript.MS_ON if enabled else mapscript.MS_OFF - self.set_metadata("wms_enable_request", " ".join(('%s' if enabled else "!%s") % c for c in requests)) - - def get_type_name(self): - return { - 0: "POINT", - 1: "LINESTRING", - 2: "POLYGON", - 3: "RASTER", - 4: "ANNOTATION", - }[self.ms.type] - - def get_proj4(self): - return self.ms.getProjection() - - def get_extent(self): - extent = self.ms.getExtent() - return stores.Extent(extent.minx, extent.miny, extent.maxx, extent.maxy) - - def get_latlon_extent(self): - rect = mapscript.rectObj(*self.get_extent()) - res = rect.project(mapscript.projectionObj(self.get_proj4()), - mapscript.projectionObj('+init=epsg:4326')) - return stores.Extent(rect.minx, rect.miny, rect.maxx, rect.maxy) - - def get_fields(self): - fields = self.get_metadata("gml_include_items", "") - - if fields == "all": - # TODO: Get fields from feature type - raise NotImplemented() - elif not fields: - return [] - else: - fields = fields.split(",") - return fields - - def iter_fields(self): - return iter(self.get_fields()) - - def iter_classes(self): - for i in xrange(self.ms.numclasses): - yield Class(self.ms.getClass(i)) - - def get_styles(self): - return set(clazz.ms.group for clazz in self.iter_classes()) - - def iter_styles(self): - return iter(self.get_styles()) - - def get_SLD(self): - return self.ms.generateSLD().decode("LATIN1").encode("UTF8") - - def add_style_sld(self, mf, s_name, new_sld): - - # Because we do not want to apply the sld to real layers by mistake - # we need to rename it to something we are sure is not used. - sld_layer_name = "__mra_tmp_template" - - # Most xml parsers will have trouble with the kind of mess we get as sld. - # Mostly because we haven't got the proper declarations, we fallback to - # an html parser, which luckily is much more forgiving. - from xml.dom.minidom import parseString - xmlsld = parseString(new_sld) - - try: - xmlsld.firstChild.getElementsByTagName("NamedLayer")[0]\ - .getElementsByTagName("Name")[0].firstChild.data = sld_layer_name - except: - raise ValueError("Bad sld (No NamedLayer/Name)") - - # Remove encoding ? - # @wapiflapi Mapscript ne gère pas les espaces... - new_sld = xmlsld.toxml() - - ms_template_layer = self.ms.clone() - ms_template_layer.name = sld_layer_name - mf.ms.insertLayer(ms_template_layer) - - try: - ms_template_layer.applySLD(new_sld, sld_layer_name) - except: - raise ValueError("Unable to access storage.") - - for i in xrange(ms_template_layer.numclasses): - ms_class = ms_template_layer.getClass(i) - ms_class.group = s_name - self.ms.insertClass(ms_class) - - mf.ms.removeLayer(ms_template_layer.index) - - - def set_default_style(self, mf): - - if self.ms.type == mapscript.MS_LAYER_POINT: - self.ms.tolerance = 8 - self.ms.toleranceunits = 6 - s_name = 'default_point' - elif self.ms.type == mapscript.MS_LAYER_LINE: - self.ms.tolerance = 8 - self.ms.toleranceunits = 6 - s_name = 'default_line' - elif self.ms.type == mapscript.MS_LAYER_POLYGON: - self.ms.tolerance = 0 - self.ms.toleranceunits = 6 - s_name = 'default_polygon' - else: - return - - try: - style = open(os.path.join(os.path.dirname(__file__), "%s.sld" % s_name)).read() - except IOError, OSError: - return - - self.add_style_sld(mf, s_name, style) - self.ms.classgroup = s_name - - def remove_style(self, s_name): - for c_index in reversed(xrange(self.ms.numclasses)): - c = self.ms.getClass(c_index) - if c.group == s_name: - self.ms.removeClass(c_index) - break - else: - raise KeyError(s_name) - - def update(self, metadata): - self.update_metadatas(metadata) - - -class LayerGroup(object): - """ - """ - - # TODO: We need to handle the order of the layers in a group. - - def __init__(self, name, mapfile): - """ - """ - - self.name = name - self.mapfile = mapfile - - def iter_layers(self): - return self.mapfile.iter_layers(meta={"wms_group_name":self.name}) - - def get_layers(self): - return list(self.iter_layers()) - - def add_layer(self, layer): - layer.ms.group = self.name - layer.set_metadata("wms_group_name", self.name) - for k, v in self.mapfile.get_mra_metadata("layergroups")[self.name]: - layer.set_metadata("wms_group_%s" % k, v) - self.mapfile.move_layer_down(layer.ms.name) - - def add(self, *args): - for layer in args: - if isinstance(layer, basestring): - layer = self.mapfile.get_layer(layer) - self.add_layer(layer) - - def remove_layer(self, layer): - layer.ms.group = None - for mkey in layer.get_metadata_keys(): - # (We really do not want to use iter_metadata_keys()) - if mkey.startswith("wms_group_"): - layer.del_metadata(mkey) - - def remove(self, *args): - for layer in args: - if isinstance(layer, basestring): - layer = mapfile.get_layer(layer) - self.remove_layer(layer) - - def clear(self): - # Remove all the layers from this group. - for layer in self.mapfile.iter_layers(attr={"group": self.name}): - self.remove_layer(layer) - - def get_latlon_extent(self): - layers = self.get_layers() - if not layers: - return stores.Extent(0, 0, 0, 0) - - extent = layers[0].get_latlon_extent() - for layer in layers[1:]: - e = layer.get_latlon_extent() - extent.addX(e.minX(), e.maxX()) - extent.addY(e.minY(), e.maxY()) - - return extent - -class LayerModel(MetadataMixin): - """ - """ - - def __init__(self, backend): - self.ms = backend - self.name = self.get_mra_metadata("name", None) - - def get_extent(self): - extent = self.ms.getExtent() - return stores.Extent(extent.minx, extent.miny, extent.maxx, extent.maxy) - - def get_latlon_extent(self): - rect = mapscript.rectObj(*self.get_extent()) - res = rect.project(mapscript.projectionObj(self.ms.getProjection()), - mapscript.projectionObj('+init=epsg:4326')) - return stores.Extent(rect.minx, rect.miny, rect.maxx, rect.maxy) - - def get_proj4(self): - return self.ms.getProjection() - - def get_wkt(self): - return tools.proj4_to_wkt(self.ms.getProjection()) - - def get_authority(self): - return tools.wkt_to_authority(self.get_wkt()) - - def get_authority_name(self): - return self.get_authority()[0] - - def get_authority_code(self): - return self.get_authority()[1] - - -class FeatureTypeModel(LayerModel): - """ - """ - - def update(self, ws, ft_name, ds_name, metadata): - - ds = ws.get_datastore(ds_name) - ft = ds[ft_name] - self.name = ft_name - - # Set basic attributes. - self.ms.name = "ft:%s:%s:%s" % (ws.name, ds_name, ft_name) - self.ms.status = mapscript.MS_OFF - self.ms.type = ft.get_geomtype_mapscript() - self.ms.setProjection(ft.get_proj4()) - self.ms.setExtent(*ft.get_extent()) - - # Configure the connection to the store. - # This is a little hacky as we have to translate stuff... - info = ws.get_datastore_info(ds_name) - cparam = info["connectionParameters"] - if cparam.get("dbtype", None) in ["postgis", "postgres", "postgresql"]: - self.ms.connectiontype = mapscript.MS_POSTGIS - connection = "dbname=%s port=%s host=%s " % (cparam["database"], cparam["port"], cparam["host"]) - connection += " ".join("%s=%s" % (p, cparam[p]) for p in ["user", "password"] if p in cparam) - self.ms.connection = connection - self.ms.data = "%s FROM %s" % (ds[ft_name].get_geometry_column(), ft_name) - self.set_metadata("ows_extent", "%s %s %s %s" % - (ft.get_extent().minX(), ft.get_extent().minY(), - ft.get_extent().maxX(), ft.get_extent().maxY())) - #elif cpram["dbtype"] in ["shp", "shapefile"]: - else: - self.ms.connectiontype = mapscript.MS_SHAPEFILE - url = urlparse.urlparse(cparam["url"]) - self.ms.data = tools.get_resource_path(url.path) - - # TODO: strip extention. - #else: - # raise ValueError("Unhandled type '%s'" % info["dbtype"]) - - # Deactivate wms and wfs requests, because we are a virtual layer. - self.set_metadatas({ - "wms_enable_request": "!GetCapabilities !GetMap !GetFeatureInfo !GetLegendGraphic", - "wfs_enable_request": "!GetCapabilities !DescribeFeatureType !GetFeature", - }) - - # Update mra metadatas, and make sure the mandatory ones are left untouched. - self.update_mra_metadatas(metadata) - self.update_mra_metadatas({"name": ft_name, "type": "featuretype", "storage": ds_name, - "workspace": ws.name, "is_model": True}) - - def configure_layer(self, ws, layer, enabled=True): - - plugins.extend("pre_configure_vector_layer", self, ws, layer) - - # We must also update all our personal attributes (type, ...) - # because we might not have been cloned. - - layer.ms.type = self.ms.type - layer.ms.setProjection(self.ms.getProjection()) - layer.ms.setExtent(self.ms.extent.minx, self.ms.extent.miny, - self.ms.extent.maxx, self.ms.extent.maxy) - layer.ms.data = self.ms.data - layer.ms.connectiontype = self.ms.connectiontype - layer.ms.connection = self.ms.connection - - layer.update_mra_metadatas({ - "name": self.get_mra_metadata("name"), - "type": self.get_mra_metadata("type"), - "storage": self.get_mra_metadata("storage"), - "workspace": self.get_mra_metadata("workspace"), - "is_model": False, - }) - - layer.update_metadatas({ - "wfs_name": layer.get_metadata("wms_name"), - "wfs_title": layer.get_metadata("wms_title"), - "wfs_abstract": layer.get_metadata("wms_abstract"), - }) - - if enabled: - layer.set_metadata("wfs_enable_request", - "GetCapabilities GetFeature DescribeFeatureType") - - # Configure the layer based on information from the store. - ds = ws.get_datastore(self.get_mra_metadata("storage")) - ft = ds[self.get_mra_metadata("name")] - - # Configure the different fields. - field_names = [] - for field in ft.iterfields(): - layer.set_metadatas({ - "gml_%s_alias" % field.get_name(): field.get_name(), - "gml_%s_type" % field.get_name(): field.get_type_gml(), - # TODO: Add gml_<field name>_precision, gml_<field name>_width - }) - field_names.append(field.get_name()) - - geometry_column = ft.get_geometry_column() - if geometry_column == None: - geometry_column = "geometry" - layer.set_metadatas({ - "ows_include_items": ",".join(field_names), - "gml_include_items": ",".join(field_names), - "gml_geometries": geometry_column, - "gml_%s_type" % geometry_column: ft.get_geomtype_gml(), - # TODO: Add gml_<geometry name>_occurances, - "wfs_srs": "EPSG:4326", - "wfs_getfeature_formatlist": "OGRGML,SHAPEZIP", - }) - - if ft.get_fid_column() != None: - layer.set_metadatas({ - "wfs_featureid": ft.get_fid_column(), - "gml_featureid": ft.get_fid_column(), - }) - - plugins.extend("post_configure_vector_layer", self, ws, ds, ft, layer) - - -class CoverageModel(LayerModel): - """ - """ - - def update(self, ws, c_name, cs_name, metadata): - - cs = ws.get_coveragestore(cs_name) - self.name = c_name - - # Set basic attributes. - self.ms.name = "c:%s:%s" % (cs_name, c_name) - self.ms.status = mapscript.MS_OFF - self.ms.type = mapscript.MS_LAYER_RASTER - self.ms.setProjection(cs.get_proj4()) - self.ms.setExtent(*cs.get_extent()) - self.ms.setProcessingKey("RESAMPLE","AVERAGE") - - # Configure the connection to the store. - # This is a little hacky as we have to translate stuff... - info = ws.get_coveragestore_info(cs_name) - cparam = info["connectionParameters"] - - #if cparam["dbtype"] in ["tif", "tiff"]: - self.ms.connectiontype = mapscript.MS_RASTER - url = urlparse.urlparse(cparam["url"]) - self.ms.data = tools.get_resource_path(url.path) - # TODO: strip extention. - #else: - # raise ValueError("Unhandled type '%s'" % cparam["dbtype"]) - - # Deactivate wms and wcs requests, because we are a virtual layer. - self.set_metadatas({ - "wms_enable_request": "!GetCapabilities !GetMap !GetFeatureInfo !GetLegendGraphic", - "wcs_enable_request": "!GetCapabilities !DescribeCoverage !GetCoverage", - }) - - # Update mra metadatas, and make sure the mandatory ones are left untouched. - self.update_mra_metadatas(metadata) - self.update_mra_metadatas({"name": c_name, "type": "coverage", "storage": cs_name, - "workspace": ws.name, "is_model": True}) - - def configure_layer(self, ws, layer, enabled=True): - - plugins.extend("pre_configure_raster_layer", self, ws, layer) - - # We must also update all our personal attributes (type, ...) - # because we might not have been cloned. - - layer.ms.type = self.ms.type - layer.ms.setProjection(self.ms.getProjection()) - layer.ms.setExtent(self.ms.extent.minx, self.ms.extent.miny, - self.ms.extent.maxx, self.ms.extent.maxy) - layer.ms.setProcessingKey("RESAMPLE","AVERAGE") - layer.ms.data = self.ms.data - layer.ms.connectiontype = self.ms.connectiontype - layer.ms.connection = self.ms.connection - - layer.update_mra_metadatas({ - "name": self.get_mra_metadata("name"), - "type": self.get_mra_metadata("type"), - "storage": self.get_mra_metadata("storage"), - "workspace": self.get_mra_metadata("workspace"), - "is_model": False, - }) - - layer.set_metadatas({ - "wfs_name": layer.get_metadata("wms_name"), - "wfs_title": layer.get_metadata("wms_title"), - "wfs_abstract": layer.get_metadata("wms_abstract"), - # TODO: wfs_keywordlist, wcs_srs, wcs_getfeature_formatlist... - }) - - if enabled: - layer.set_metadata("wcs_enable_request", "GetCapabilities GetCoverage DescribeCoverage") - - plugins.extend("post_configure_raster_layer", self, ws, layer) - - -class Workspace(object): - # TODO - pass - -class MapfileWorkspace(Workspace): - """ A workspace representing a whole mapfile. - This is currently the only existing type of workspace, - but there should be others that can handle subsets of - the mapfile. - """ - - def __init__(self, mapfile): - # We are obvliously the default workspace. - self.name = mapfile.get_default_workspace_name() - self.mapfile = mapfile - - def save(self): - """Saves the workspace to disk, same as calling save on the - associated mapfile. - """ - self.mapfile.save() - - # Stores: - def get_store(self, st_type, name): - st_type = st_type if st_type.endswith("s") else st_type + "s" - cparam = get_store_connection_string(self.get_store_info(st_type, name)) - if st_type == "datastores": - return stores.Datastore(cparam) - elif st_type == "coveragestores": - return stores.Coveragestore(cparam) - - def get_store_info(self, st_type, name): - st_type = st_type if st_type.endswith("s") else st_type + "s" - info = self.mapfile.get_mra_metadata(st_type, {})[name].copy() - info["name"] = name - return info - - def iter_store_names(self, st_type): - st_type = st_type if st_type.endswith("s") else st_type + "s" - return self.mapfile.get_mra_metadata(st_type, {}).iterkeys() - - def iter_stores(self, st_type): - st_type = st_type if st_type.endswith("s") else st_type + "s" - return self.mapfile.get_mra_metadata(st_type, {}).iteritems() - - def create_store(self, st_type, name, configuration): - st_type = st_type if st_type.endswith("s") else st_type + "s" - with self.mapfile.mra_metadata(st_type, {}) as stores: - if name in stores: - raise KeyExists(name) - stores[name] = configuration - - def update_store(self, st_type, name, configuration): - st_type = st_type if st_type.endswith("s") else st_type + "s" - with self.mapfile.mra_metadata(st_type, {}) as stores: - stores[name].update(configuration) - - def delete_store(self, st_type, name): - st_type = st_type if st_type.endswith("s") else st_type + "s" - with self.mapfile.mra_metadata(st_type, {}) as stores: - del stores[name] - - # Datastores: - - def get_datastore(self, name): - """Returns a store.Datastore object from the workspace.""" - return self.get_store("datastores", name) - - def get_datastore_info(self, name): - """Returns info for a datastore from the workspace.""" - return self.get_store_info("datastores", name) - - def iter_datastore_names(self): - """Return an iterator over the datastore names.""" - return self.iter_store_names("datastores") - - def iter_datastores(self): - """Return an iterator over the datastore (names, configuration).""" - return self.iter_stores("datastores") - - def create_datastore(self, name, configuration): - """Creates a new datastore.""" - return self.create_store("datastores", name, configuration) - - def update_datastore(self, name, configuration): - """Update a datastore.""" - return self.update_store("datastores", name, configuration) - - def delete_datastore(self, name): - """Delete a datastore.""" - return self.delete_store("datastores", name) - - # Coveragestores (this is c/p from datastores): - - def get_coveragestore(self, name): - """Returns a store.Coveragestore object from the workspace.""" - return self.get_store("coveragestores", name) - - def get_coveragestore_info(self, name): - """Returns info for a coveragestore from the workspace.""" - return self.get_store_info("coveragestores", name) - - def iter_coveragestore_names(self): - """Return an iterator over the coveragestore names.""" - return self.iter_store_names("coveragestores") - - def iter_coveragestores(self): - """Return an iterator over the coveragestore (names, configuration).""" - return self.iter_stores("coveragestores") - - def create_coveragestore(self, name, configuration): - """Creates a new coveragestore.""" - return self.create_store("coveragestores", name, configuration) - - def update_coveragestore(self, name, configuration): - """Update a coveragestore.""" - return self.update_store("coveragestores", name, configuration) - - def delete_coveragestore(self, name): - """Delete a coveragestore.""" - return self.delete_store("coveragestores", name) - - # Feature types - - def iter_featuretypemodels(self, ds_name=None, **kwargs): - kwargs.setdefault("mra", {}).update({"type":"featuretype", "is_model":True}) - if ds_name != None: - kwargs["mra"].update({"storage":ds_name, "workspace":self.name}) - for ms_layer in self.mapfile.iter_ms_layers(**kwargs): - yield FeatureTypeModel(ms_layer) - - def get_featuretypemodel(self, ft_name, ds_name): - # Improvement: Use get by name combined with a coverage-specific naming. - try: - return next(self.iter_featuretypemodels(ds_name, mra={"name":ft_name})) - except StopIteration: - raise KeyError((ds_name, ft_name)) - - def has_featuretypemodel(self, ft_name, ds_name): - # Improvement: See get_featuretypemodel - try: - self.get_featuretypemodel(ft_name, ds_name) - except KeyError: - return False - else: - return True - - def create_featuretypemodel(self, ft_name, ds_name, metadata={}): - if self.has_featuretypemodel(ft_name, ds_name): - raise KeyExists(ft_name) - - ft = FeatureTypeModel(mapscript.layerObj(self.mapfile.ms)) - ft.update(self, ft_name, ds_name, metadata) - return ft - - def update_featuretypemodel(self, ft_name, ds_name, metadata={}): - ft = self.get_featuretypemodel(ft_name, ds_name) - ft.update(self, ft_name, ds_name, metadata) - - def delete_featuretypemodel(self, ft_name, ds_name): - try: - next(self.mapfile.iter_layers(mra={"workspace":self.name, "type":"featuretype", - "storage":ds_name, "name":ft_name})) - except StopIteration: - pass # No layers use our featuretyp, all OK. - else: - raise ValueError("The featuretype '%s' can't be delete because it is used." % ft_name) - - ft = self.get_featuretypemodel(ft_name, ds_name) - self.mapfile.ms.removeLayer(ft.ms.index) - - # Coverages - - def iter_coveragemodels(self, cs_name=None, **kwargs): - kwargs.setdefault("mra", {}).update({"type":"coverage", "is_model":True}) - if cs_name != None: - kwargs["mra"].update({"storage":cs_name, "workspace":self.name}) - for ms_layer in self.mapfile.iter_ms_layers(**kwargs): - yield CoverageModel(ms_layer) - - def get_coveragemodel(self, c_name, cs_name): - # Improvement: Use get by name combined with a coverage-specific naming. - try: - return next(self.iter_coveragemodels(cs_name, mra={"name":c_name})) - except StopIteration: - raise KeyError((cs_name, c_name)) - - def has_coveragemodel(self, c_name, cs_name): - # Improvement: See get_coveragemodel - try: - self.get_coveragemodel(c_name, cs_name) - except KeyError: - return False - else: - return True - - def create_coveragemodel(self, c_name, cs_name, metadata={}): - if self.has_coveragemodel(c_name, cs_name): - raise KeyExists(c_name) - - c = CoverageModel(mapscript.layerObj(self.mapfile.ms)) - c.update(self, c_name, cs_name, metadata) - return c - - def update_coveragemodel(self, c_name, cs_name, metadata={}): - c = self.get_coveragemodel(c_name, cs_name) - c.update(self, c_name, cs_name, metadata) - - def delete_coveragemodel(self, c_name, cs_name): - try: - next(self.mapfile.iter_layers(mra={"workspace":self.name, "type":"coverage", - "storage":cs_name, "name":c_name})) - except StopIteration: - pass # No layers use our featuretyp, all OK. - else: - raise ValueError("The coverage '%s' can't be delete because it is used." % c_name) - - c = self.get_coveragemodel(c_name, cs_name) - self.mapfile.ms.removeLayer(c.ms.index) - - # All the above :) - - def get_model(self, m_name, s_type, s_name): - - if s_type == "coverage": - return self.get_coveragemodel(m_name, s_name) - elif s_type == "featuretype": - return self.get_featuretypemodel(m_name, s_name) - else: - raise ValueError("Bad storage type '%s'." % s_type) - - -def create_mapfile(path, map_name, data): - if os.path.exists("%s.map" % path): - raise KeyExists(map_name) - - mf = mapscript.mapObj() - mf.name = map_name - - # The following could be defined in <mapfile.py>: - - mf.web.metadata.set("ows_name", map_name) - mf.web.metadata.set("ows_title", data.get("title", map_name)) - mf.web.metadata.set("ows_abstract", data.get("abstract", "")) - - # Set default values: - # It should be configurable to the future. - - # mf.web.metadata.set("ows_keywordlist", "") - # mf.web.metadata.set("ows_keywordlist_vocabulary", "") - # + ows_keywordlist_[vocabulary’s name]_items - # mf.web.metadata.set("wms_onlineresource", "") - # mf.web.metadata.set("wfs_onlineresource", "") - # mf.web.metadata.set("wms_service_onlineresource", "") - # mf.web.metadata.set("wfs_service_onlineresource", "") - mf.web.metadata.set("wms_srs", "EPSG:4326") - mf.web.metadata.set("wfs_srs", "EPSG:4326") - mf.web.metadata.set("wms_bbox_extended", "true") - # mf.web.metadata.set("wms_resx", "") - # mf.web.metadata.set("wms_resy", "") - - mf.web.metadata.set("ows_schemas_location", - "http://schemas.opengeospatial.net") - mf.web.metadata.set("ows_updatesequence", "foo") - mf.web.metadata.set("ows_addresstype", "foo") - mf.web.metadata.set("ows_address", "foo") - mf.web.metadata.set("ows_city", "foo") - mf.web.metadata.set("ows_stateorprovince", "foo") - mf.web.metadata.set("ows_postcode", "foo") - mf.web.metadata.set("ows_contactperson", "foo") - mf.web.metadata.set("ows_contactposition", "foo") - mf.web.metadata.set("ows_contactorganization", "foo") - mf.web.metadata.set("ows_contactelectronicmailaddress", "foo") - mf.web.metadata.set("ows_contactfacsimiletelephone", "foo") - mf.web.metadata.set("ows_contactvoicetelephone", "foo") - mf.web.metadata.set("wms_fees", "none") - mf.web.metadata.set("wfs_fees", "none") - mf.web.metadata.set("wms_accessconstraints", "none") - mf.web.metadata.set("wfs_accessconstraints", "none") - # mf.web.metadata.set("ows_attribution_logourl_format", "") - # mf.web.metadata.set("ows_attribution_logourl_height", "") - # mf.web.metadata.set("ows_attribution_logourl_href", "") - # mf.web.metadata.set("ows_attribution_logourl_width", "") - # mf.web.metadata.set("ows_attribution_onlineresource", "") - # mf.web.metadata.set("ows_attribution_title", "") - - mf.web.metadata.set("wms_enable_request", - "GetCapabilities GetMap GetFeatureInfo GetLegendGraphic") - mf.web.metadata.set("wfs_enable_request", - "GetCapabilities DescribeFeatureType GetFeature") - mf.web.metadata.set("ows_sld_enabled", "true") - mf.web.metadata.set("wms_getcapabilities_version", "1.3.0") - mf.web.metadata.set("wfs_getcapabilities_version", "1.0.0") - # mf.web.metadata.set("wms_getmap_formatlist", "") - # mf.web.metadata.set("wms_getlegendgraphic_formatlist", "") - mf.web.metadata.set("wms_feature_info_mime_type", - "application/vnd.ogc.gml,text/plain") - # TODO: text/html - mf.web.metadata.set("wms_encoding", "UTF-8") - mf.web.metadata.set("wfs_encoding", "UTF-8") - - # mf.web.metadata.set("wms_timeformat", "") - # mf.web.metadata.set("wms_languages", "") - # mf.web.metadata.set("wms_layerlimit", "") - # mf.web.metadata.set("wms_rootlayer_abstract", "") - # mf.web.metadata.set("wms_rootlayer_keywordlist", "") - # mf.web.metadata.set("wms_rootlayer_title", "") - # mf.web.metadata.set("wfs_maxfeatures", "") - # mf.web.metadata.set("wfs_feature_collection", "") - # mf.web.metadata.set("wfs_namespace_uri", "") - # mf.web.metadata.set("wfs_namespace_prefix", "") - - mf.status = mapscript.MS_ON - mf.setSize(256,256) - mf.maxsize = 4096 - mf.resolution = 96 - mf.imagetype = 'png' - mf.imagecolor.setRGB(255,255,255) - mf.setProjection("init=epsg:4326") - mf.setExtent(-180,-90,180,90) - mf.units = mapscript.MS_DD - - mf.save("%s.map" % path) - - -class Mapfile(MetadataMixin): - """ - """ - - def __init__(self, path, root=None): - - if root != None: - full_path = os.path.realpath(os.path.join(root, "%s.map" % path)) - if not full_path.startswith(root): - raise IOError("mapfile '%s' outside root directory." % (path)) - path = full_path - if isinstance(path, mapscript.mapObj): - self.path = None - self.ms = path - else: - self.path = path - self.ms = mapscript.mapObj(self.path) - - self.filename = os.path.basename(self.path) - - # We have one workspace that represents the file. - self.__default_workspace = MapfileWorkspace(self) - - def save(self, path=None): - if path is None: - path = self.path - self.ms.save(path) - - def rawtext(self): - open(self.path, "r").read() - - def update(self, configuration): - raise NotImplemented() - - # Layers: - - def iter_ms_layers(self, attr={}, meta={}, mra={}): - def check(f, v): - return f(v) if callable(f) else f == v - - for l in xrange(self.ms.numlayers): - ms_layer = self.ms.getLayer(l) - if not all(check(checker, getattr(ms_layer, k, None)) for k, checker in attr.iteritems()): - continue - if not all(check(checker, metadata.get_metadata(ms_layer, k, None)) for k, checker in meta.iteritems()): - continue - if not all(check(checker, metadata.get_mra_metadata(ms_layer, k, None)) for k, checker in mra.iteritems()): - continue - yield ms_layer - - def iter_layers(self, **kwargs): - kwargs.setdefault("mra", {}).update({"is_model": lambda x: x != True}) - for ms_layer in self.iter_ms_layers(**kwargs): - yield Layer(ms_layer) - - def get_layer(self, l_name): - try: - return next(self.iter_layers(attr={"name": l_name})) - except StopIteration: - raise KeyError(l_name) - - def move_layer_down(self, l_name): - layer = self.get_layer(l_name) - self.ms.moveLayerDown(layer.ms.index) - - def has_layer(self, l_name): - try: - self.get_layer(l_name) - except KeyError: - return False - else: - return True - - def get_layer_wsm(self, l_name): - layer = self.get_layer(l_name) - ws = self.get_workspace(layer.get_mra_metadata("workspace")) - model = ws.get_model(m_name=layer.get_mra_metadata("name"), - s_type=layer.get_mra_metadata("type"), - s_name=layer.get_mra_metadata("storage")) - return layer, ws, model - - def create_layer(self, ws, model, l_name, l_enabled, l_metadata={}): - # First create the layer, then configure it. - - if self.has_layer(l_name): - raise KeyExists(l_name) - - # We still clone, because we have to start from something, - # but everything should be configured() anyway. - layer = Layer(model.ms.clone()) - self.ms.insertLayer(layer.ms) - - layer.ms.name = l_name - layer.enable(l_enabled) - - # is queryable (by default): - layer.ms.template = "foo.html" # TODO: Support html format response - - l_metadata["wms_name"] = l_name - - l_metadata.setdefault("wms_title", l_name) - l_metadata.setdefault("wms_abstract", l_name) - l_metadata.setdefault("wms_bbox_extended", "true") - # TODO: Add other default values as above: - # wms_keywordlist, wms_keywordlist_vocabulary - # wms_keywordlist_<vocabulary>_items - # wms_srs - # wms_dataurl_(format|href) - # ows_attribution_(title|onlineresource) - # ows_attribution_logourl_(href|format|height|width) - # ows_identifier_(authority|value) - # ows_authorityurl_(name|href) - # ows_metadataurl_(type|href|format) - - # TODO: pass correct data (title, abstract, ...) to layer.update() - layer.update(l_metadata) - - model.configure_layer(ws, layer, l_enabled) - - layer.set_default_style(self) - - def delete_layer(self, l_name): - layer = self.get_layer(l_name) - - self.ms.removeLayer(layer.ms.index) - - # Layergroups - - def create_layergroup(self, lg_name, mra_metadata={}): - with self.mra_metadata("layergroups", {}) as layergroups: - if lg_name in layergroups: - raise KeyExists(lg_name) - layergroups[lg_name] = mra_metadata - return LayerGroup(lg_name, self) - - def iter_layergroups(self): - return (LayerGroup(name, self) for name in self.get_mra_metadata("layergroups", {}).iterkeys()) - - def get_layergroup(self, lg_name): - if lg_name in self.get_mra_metadata("layergroups", {}): - return LayerGroup(lg_name, self) - else: - raise KeyError(lg_name) - - def add_to_layergroup(self, lg_name, *args): - lg = self.get_layergroup(lg_name) - lg.add(*args) - - def remove_from_layergroup(self, lg_name, *args): - lg = self.get_layergroup(lg_name) - lg.remove(*args) - - def delete_layergroup(self, lg_name): - layer_group = self.get_layergroup(lg_name) - # Remove all the layers from this group. - for layer in self.iter_layers(attr={"group": layer_group.name}): - layer_group.remove(layer) - # Remove the group from mra metadata. - with self.mra_metadata("layergroups", {}) as layergroups: - del layergroups[lg_name] - - # Styles: - - def iter_styles(self): - return iter(self.get_styles()) - - def get_styles(self): - # The group name is the style's name. - - styles = set() - for layer in self.iter_layers(): - for clazz in layer.iter_classes(): - styles.add(clazz.ms.group) - - return styles - - def get_style_sld(self, s_name): - # Because styles do not really exist here, we first need to find - # a layer that has the style we want. - - for layer in self.iter_layers(): - if s_name in layer.get_styles(): - break - else: - raise KeyError(s_name) - - # This is a ugly hack. We clone the layer and remove all the other styles. - # Then we ask mapscript to generate the sld, but aprently for that the - # cloned style needs to be in the mapfile... so be it. - clone = layer.ms.clone() - for c_index in reversed(xrange(clone.numclasses)): - c = clone.getClass(c_index) - if c.group != s_name: - clone.removeClass(c_index) - - self.ms.insertLayer(clone) - sld = Layer(clone).get_SLD() - self.ms.removeLayer(clone.index) - - return sld - - # Workspaces: - - def get_default_workspace_name(self): - return self.get_mra_metadata("default_workspace", "default") - - def set_default_workspace_name(self, name): - self.set_mra_metadata("default_workspace", name) - - def iter_workspaces(self): - """iter_ates over the workspaces managed by a mapfile. - For current version, only "default" workspace is available which - correspond to the current mapfile. The relationship between default - workspace and mapfile is one to one. - However there is currently work underway to change this... - """ - yield self.get_default_workspace() - - def get_workspaces(self): - """Gets workspaces from mapfile that match all the specified conditions. - For the moment this is equivalent to iter_workspaces, because workpspaces - are still a "virtual" notion and do not really exist. - """ - return list(self.iter_workspaces()) - - def get_workspace(self, name): - if name != self.get_default_workspace_name(): - raise KeyError(name) - return self.get_default_workspace() - - def get_default_workspace(self): - return self.__default_workspace - - # Let"s delegate other stuff to the default workspace. - # def __getattr__(self, name): - # if hasattr(self, "__default_workspace"): - # return getattr(self.__default_workspace, name) diff --git a/src/server.py b/src/server.py index 66c6d49..bdac1ed 100755 --- a/src/server.py +++ b/src/server.py @@ -35,7 +35,6 @@ import urlparse import mralogs import logging -import mapfile from mra import MRA diff --git a/src/tools.py b/src/tools.py index e1a9c1f..14932d9 100644 --- a/src/tools.py +++ b/src/tools.py @@ -28,7 +28,6 @@ import os import yaml import sys -import mapfile import pyxml import webapp -- GitLab