1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  MapServer
5  * Purpose:  MapCache tile caching support file: Mapserver Mapfile datasource
6  * Author:   Thomas Bonfort and the MapServer team.
7  *
8  ******************************************************************************
9  * Copyright (c) 1996-2011 Regents of the University of Minnesota.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies of this Software or works derived from this Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  *****************************************************************************/
29 
30 
31 #include "mapcache.h"
32 #include "ezxml.h"
33 #include <apr_tables.h>
34 #include <apr_strings.h>
35 
36 typedef struct mapcache_source_fallback mapcache_source_fallback;
37 struct mapcache_source_fallback {
38   mapcache_source source;
39   apr_array_header_t *sources;
40 };
41 
42 /**
43  * \private \memberof mapcache_source_fallback
44  * \sa mapcache_source::render_map()
45  */
_mapcache_source_fallback_render_map(mapcache_context * ctx,mapcache_source * psource,mapcache_map * map)46 void _mapcache_source_fallback_render_map(mapcache_context *ctx, mapcache_source *psource, mapcache_map *map)
47 {
48   mapcache_source_fallback *source = (mapcache_source_fallback*)psource;
49   mapcache_source *subsource;
50   int i;
51   subsource = APR_ARRAY_IDX(source->sources,0,mapcache_source*);
52   mapcache_source_render_map(ctx, subsource, map);
53 
54   if(GC_HAS_ERROR(ctx)) {
55     int first_error = ctx->get_error(ctx);
56     char *first_error_message = ctx->get_error_message(ctx);
57     ctx->log(ctx,MAPCACHE_INFO,
58         "failed render on primary source \"%s\" on tileset \"%s\". Falling back on secondary sources",
59         subsource->name,map->tileset->name);
60     ctx->clear_errors(ctx);
61     for(i=1; i<source->sources->nelts; i++) {
62       subsource = APR_ARRAY_IDX(source->sources,i,mapcache_source*);
63       mapcache_source_render_map(ctx, subsource, map);
64       if(GC_HAS_ERROR(ctx)) {
65         ctx->log(ctx,MAPCACHE_INFO,
66             "failed render on fallback source \"%s\" of tileset \"%s\". Continuing with other fallback sources if available",
67             subsource->name,map->tileset->name);
68         ctx->clear_errors(ctx);
69         continue;
70       } else {
71         return;
72       }
73     }
74     /* all backends failed, return primary error message */
75     ctx->set_error(ctx,first_error,first_error_message);
76     return;
77   }
78 }
79 
_mapcache_source_fallback_query(mapcache_context * ctx,mapcache_source * psource,mapcache_feature_info * fi)80 void _mapcache_source_fallback_query(mapcache_context *ctx, mapcache_source *psource, mapcache_feature_info *fi)
81 {
82   mapcache_source_fallback *source = (mapcache_source_fallback*)psource;
83   mapcache_source *subsource;
84   int i;
85   subsource = APR_ARRAY_IDX(source->sources,0,mapcache_source*);
86   mapcache_source_query_info(ctx, subsource, fi);
87 
88   if(GC_HAS_ERROR(ctx)) {
89     int first_error = ctx->get_error(ctx);
90     char *first_error_message = ctx->get_error_message(ctx);
91     ctx->log(ctx,MAPCACHE_INFO,
92         "failed query_info on primary source \"%s\" on tileset \"%s\". Falling back on secondary sources",
93         subsource->name,fi->map.tileset->name);
94     ctx->clear_errors(ctx);
95     for(i=1; i<source->sources->nelts; i++) {
96       subsource = APR_ARRAY_IDX(source->sources,i,mapcache_source*);
97       mapcache_source_query_info(ctx, subsource, fi);
98       if(GC_HAS_ERROR(ctx)) {
99         ctx->log(ctx,MAPCACHE_INFO,
100             "failed query_info on fallback source \"%s\" of tileset \"%s\". Continuing with other fallback sources if available",
101             subsource->name,fi->map.tileset->name);
102         ctx->clear_errors(ctx);
103         continue;
104       } else {
105         return;
106       }
107     }
108     /* all backends failed, return primary error message */
109     ctx->set_error(ctx,first_error,first_error_message);
110     return;
111   }
112   ctx->set_error(ctx,500,"fallback source does not support queries");
113 }
114 
115 /**
116  * \private \memberof mapcache_source_fallback
117  * \sa mapcache_source::configuration_parse()
118  */
_mapcache_source_fallback_configuration_parse_xml(mapcache_context * ctx,ezxml_t node,mapcache_source * psource,mapcache_cfg * config)119 void _mapcache_source_fallback_configuration_parse_xml(mapcache_context *ctx, ezxml_t node, mapcache_source *psource, mapcache_cfg *config)
120 {
121   ezxml_t cur_node;
122   mapcache_source_fallback *source = (mapcache_source_fallback*)psource;
123   source->sources = apr_array_make(ctx->pool,3,sizeof(mapcache_source*));
124   for(cur_node = ezxml_child(node,"source"); cur_node; cur_node = cur_node->next) {
125     mapcache_source *refsource = mapcache_configuration_get_source(config, cur_node->txt);
126     if(!refsource) {
127       ctx->set_error(ctx, 400, "fallback source \"%s\" references source \"%s\","
128                      " but it is not configured (hint:referenced sources must be declared before this fallback source in the xml file)", psource->name, cur_node->txt);
129       return;
130     }
131     APR_ARRAY_PUSH(source->sources,mapcache_source*) = refsource;
132   }
133   if(source->sources->nelts == 0) {
134     ctx->set_error(ctx,400,"fallback source \"%s\" does not reference any child sources", psource->name);
135   }
136 }
137 
138 /**
139  * \private \memberof mapcache_source_fallback
140  * \sa mapcache_source::configuration_check()
141  */
_mapcache_source_fallback_configuration_check(mapcache_context * ctx,mapcache_cfg * cfg,mapcache_source * source)142 void _mapcache_source_fallback_configuration_check(mapcache_context *ctx, mapcache_cfg *cfg,
143     mapcache_source *source)
144 {
145 }
146 
mapcache_source_fallback_create(mapcache_context * ctx)147 mapcache_source* mapcache_source_fallback_create(mapcache_context *ctx)
148 {
149   mapcache_source_fallback *source = apr_pcalloc(ctx->pool, sizeof(mapcache_source_fallback));
150   if(!source) {
151     ctx->set_error(ctx, 500, "failed to allocate fallback source");
152     return NULL;
153   }
154   mapcache_source_init(ctx, &(source->source));
155   source->source.type = MAPCACHE_SOURCE_FALLBACK;
156   source->source._render_map = _mapcache_source_fallback_render_map;
157   source->source.configuration_check = _mapcache_source_fallback_configuration_check;
158   source->source.configuration_parse_xml = _mapcache_source_fallback_configuration_parse_xml;
159   source->source._query_info = _mapcache_source_fallback_query;
160   return (mapcache_source*)source;
161 }
162 
163 
164 /* vim: ts=2 sts=2 et sw=2
165 */
166