alaCarte Maps
Renderer for OpenStreetMap tiles
stylesheet_manager.cpp
Go to the documentation of this file.
1 
25 #include "server/stylesheet.hpp"
26 #include "server/cache.hpp"
29 #include "general/geodata.hpp"
32 #include "server/eval/eval.hpp"
33 #include "server/rule.hpp"
34 #include "server/job.hpp"
35 #include <math.h>
37 
38 StylesheetManager::StylesheetManager(const shared_ptr<Configuration>& config)
39  : config(config)
40  , monitorService(new boost::asio::dir_monitor(ioService))
41 {
42  stylesheetFolder = config->get<string>(opt::server::style_source);
43 }
44 
45 
46 void StylesheetManager::startStylesheetObserving(const shared_ptr<RequestManager>& manager)
47 {
48  this->manager = manager;
49  parsedStylesheets[".fallback"] = StylesheetManager::makeFallbackStylesheet(manager->getGeodata());
50 
51  fs::directory_iterator end_iter;
52 
53  boost::unique_lock<boost::shared_mutex> writeLock(stylesheetsLock);
54  for( fs::directory_iterator dir_iter(stylesheetFolder) ; dir_iter != end_iter ; ++dir_iter) {
55  if (fs::is_regular_file(dir_iter->status()) && dir_iter->path().extension() == ".mapcss" ) {
56  StylesheetManager::onNewStylesheet(dir_iter->path().stem());
57  }
58  }
59 
60  monitorService->add_directory(config->get<string>(opt::server::style_source));
61  monitorService->async_monitor(boost::bind(&StylesheetManager::onFileSystemEvent, shared_from_this(), _1, _2));
62 
63  monitorThread = boost::thread(boost::bind(&boost::asio::io_service::run, &ioService));
64 }
65 
66 
68 {
69  monitorService.reset();
70  monitorThread.join();
71 }
72 
73 bool StylesheetManager::hasStylesheet(const string& path)
74 {
75  boost::shared_lock<boost::shared_mutex> readLock(stylesheetsLock);
76 
77  auto entry = parsedStylesheets.find(path);
78  bool contained = (entry != parsedStylesheets.end());
79 
80  return contained;
81 }
82 
83 shared_ptr<Stylesheet> StylesheetManager::getStylesheet(const string& path)
84 {
85  boost::shared_lock<boost::shared_mutex> readLock(stylesheetsLock);
86 
87  auto entry = parsedStylesheets.find(path);
88 
89  shared_ptr<Stylesheet> result;
90  if (entry != parsedStylesheets.end()) {
91  result = entry->second;
92  } else {
93  result = parsedStylesheets[".fallback"];
94  }
95 
96  return result;
97 }
98 
99 // calls must be locked by write-lock
100 void StylesheetManager::onNewStylesheet(const fs::path& stylesheet_path)
101 {
102  // lock the weak_ptr to manager
103  shared_ptr<RequestManager> manager = this->manager.lock();
104  assert(manager);
105 
106  shared_ptr<Stylesheet> stylesheet;
107  int timeout = config->get<int>(opt::server::parse_timeout);
108 
109  try {
110  std::string new_filename = stylesheet_path.filename().string() + ".mapcss";
111  fs::path filename(new_filename);
112  stylesheet = Stylesheet::Load(stylesheetFolder / filename, manager->getGeodata(), timeout);
113 
114  } catch(excp::ParseException& e)
115  {
116  shared_ptr<ParserLogger> logger = *boost::get_error_info<excp::InfoParserLogger>(e);
117 
118  // Something went wrong!
119  logger->errorStream() << "Parsing of file \"" << excp::ErrorOut<excp::InfoFileName>(e, stylesheet_path.string()) << "\" failed:";
120  logger->errorStream() << excp::ErrorOut<excp::InfoWhat>(e, "unknown reason!");
121  logger->errorStream() << "In line " << excp::ErrorOut<excp::InfoFailureLine>(e) << " column " << excp::ErrorOut<excp::InfoFailureColumn>(e) << ":";
122 
123  const string* errLine = boost::get_error_info<excp::InfoFailureLineContent>(e);
124  const int* errColumn = boost::get_error_info<excp::InfoFailureColumn>(e);
125 
126  if(errLine)
127  logger->errorStream() << "'" << *errLine << "'";
128 
129  if(errColumn)
130  logger->errorStream() << string(*errColumn, ' ') << "^-here";
131 
132  return;
133  } catch(excp::TimeoutException&)
134  {
135  shared_ptr<ParserLogger> logger = boost::make_shared<ParserLogger>(stylesheet_path.string());
136 
137  logger->errorStream() << "Parsing of stylesheet " << stylesheet_path << " took more then " << timeout << " ms!";
138  logger->errorStream() << "Parsing canceled!";
139  logger->errorStream() << "You can configure the timeout via '--parse-timeout'.";
140  return;
141  }
142 
143  parsedStylesheets[stylesheet_path] = stylesheet;
144 
145  // prerenders the upmost tile as well as all higher zoomlevels that are specified in the configuration
146  manager->enqueue(boost::make_shared<MetaIdentifier>(TileIdentifier(0, 0, 0, stylesheet_path.string(), TileIdentifier::PNG)));
147 }
148 
149 // calls must be locked by write-lock
150 void StylesheetManager::onRemovedStylesheet(const fs::path& stylesheet_path)
151 {
152  // lock the weak_ptr to manager
153  shared_ptr<RequestManager> manager = this->manager.lock();
154  assert(manager);
155 
156  manager->getCache()->deleteTiles(stylesheet_path.string());
157  parsedStylesheets.erase(stylesheet_path);
158  LOG_SEV(style_log, info) << "Deleted Stylesheet[" << stylesheet_path << "] from Tile Cache and Stylesheet Cache.";
159 }
160 
161 void StylesheetManager::onFileSystemEvent(const boost::system::error_code &ec, const boost::asio::dir_monitor_event &ev)
162 {
163  typedef boost::asio::dir_monitor_event eventtype;
164 
165  if(ec != boost::system::error_code())
166  {
167  // We don't need to inform about the end of watching
168  if(ec != boost::asio::error::operation_aborted)
169  {
170  LOG_SEV(style_log, error) << "Error while watching the stylesheet folder[" << stylesheetFolder << "]:";
171  LOG_SEV(style_log, error) << ec.message();
172  }
173 
174  return;
175  }
176 
177  fs::path path = fs::path(ev.path);
178 
179  // only act on .mapcss files that additionally aren't hidden files
180  if (path.extension() == ".mapcss" && path.stem().string().find(".") != 0) {
181  path = path.stem();
182 
183  // lock is outside of functions calls so that remove + add (== changed) can be atomic
184  boost::unique_lock<boost::shared_mutex> writeLock(stylesheetsLock);
185  switch (ev.type)
186  {
187  case eventtype::added:
188  {
189  LOG_SEV(style_log, info) << "Stylesheet[" << path << "] added!";
190  onNewStylesheet(path);
191  }break;
192 
193  case eventtype::removed:
194  {
195  LOG_SEV(style_log, info) << "Stylesheet[" << path << "] removed!";
196  onRemovedStylesheet(path);
197  }break;
198 
199  case eventtype::modified:
200  {
201  LOG_SEV(style_log, info) << "Stylesheet[" << path << "] modified!";
202  onRemovedStylesheet(path);
203  onNewStylesheet(path);
204  }break;
205  default:
206  break;
207  }
208  }
209 
210  // continue to monitor the folder
211  monitorService->async_monitor(boost::bind(&StylesheetManager::onFileSystemEvent, shared_from_this(), _1, _2));
212 }
213 
214 // hard coded fallback stylesheet, used in case the default stylesheet file doesn't exist
215 shared_ptr<Stylesheet> StylesheetManager::makeFallbackStylesheet(const shared_ptr<Geodata>& geodata) {
216  shared_ptr<StyleTemplate> canvasStyle = boost::make_shared<StyleTemplate>();
217  canvasStyle->fill_color = boost::make_shared<eval::Eval<Color>>(Color((uint8)0xEF, (uint8)0xEF, (uint8)0xD0));
218 
219  std::vector<shared_ptr<Rule> > rules;
220 
221  shared_ptr<Rule> highwayNodeRule = boost::make_shared<Rule>(geodata);
222  shared_ptr<ApplySelector> highwayNodeApplier = boost::make_shared<ApplySelector>(highwayNodeRule);
223  shared_ptr<Selector> highwayNodeTagSelector = boost::make_shared<HasTagSelector>(highwayNodeRule, highwayNodeApplier, "highway");
224  highwayNodeRule->setFirstSelector(highwayNodeTagSelector);
225  shared_ptr<StyleTemplate> highwayNodeStyle = boost::make_shared<StyleTemplate>();
226  highwayNodeStyle->color = boost::make_shared<eval::Eval<Color>>(Color((uint8)0x00, (uint8)0x00, (uint8)0xFF));
227  highwayNodeStyle->width = boost::make_shared<eval::Eval<float>>(5.5);
228  highwayNodeRule->setStyleTemplate(highwayNodeStyle);
229  highwayNodeRule->setZoomBounds(16, 18);
230  highwayNodeRule->setAcceptableType(Rule::Accept_Way);
231 
232  rules.push_back(highwayNodeRule);
233 
234 
235  shared_ptr<Rule> highwayRule = boost::make_shared<Rule>(geodata);
236  shared_ptr<ApplySelector> highwayApplier = boost::make_shared<ApplySelector>(highwayRule);
237  shared_ptr<Selector> highwayTagSelector = boost::make_shared<HasTagSelector>(highwayRule, highwayApplier, "highway");
238  highwayRule->setFirstSelector(highwayTagSelector);
239  shared_ptr<StyleTemplate> highwayStyle = boost::make_shared<StyleTemplate>();
240  highwayStyle->color = boost::make_shared<eval::Eval<Color>>(Color((uint8)0x55, (uint8)0x55, (uint8)0x55));
241  highwayStyle->width = boost::make_shared<eval::Eval<float>>(2.0);
242  highwayRule->setStyleTemplate(highwayStyle);
243  highwayRule->setAcceptableType(Rule::Accept_Way);
244 
245  rules.push_back(highwayRule);
246 
247 
248  shared_ptr<Rule> highwayUpRule = boost::make_shared<Rule>(geodata);
249  shared_ptr<ApplySelector> highwayUpApplier = boost::make_shared<ApplySelector>(highwayUpRule);
250  shared_ptr<Selector> highwayUpTagSelector = boost::make_shared<HasTagSelector>(highwayUpRule, highwayUpApplier, "highway");
251  highwayUpRule->setFirstSelector(highwayUpTagSelector);
252  shared_ptr<StyleTemplate> highwayUpStyle = boost::make_shared<StyleTemplate>();
253  highwayUpStyle->width = boost::make_shared<eval::Eval<float>>(1.0);
254  highwayUpRule->setStyleTemplate(highwayUpStyle);
255  highwayUpRule->setZoomBounds(0,15);
256  highwayUpRule->setAcceptableType(Rule::Accept_Way);
257 
258  rules.push_back(highwayUpRule);
259 
260 
261  shared_ptr<Rule> forestRule = boost::make_shared<Rule>(geodata);
262  shared_ptr<ApplySelector> forestApplier = boost::make_shared<ApplySelector>(forestRule);
263  shared_ptr<Selector> forestTagSelector = boost::make_shared<TagEqualsSelector>(forestRule, forestApplier, "landuse", "forest");
264  forestRule->setFirstSelector(forestTagSelector);
265  shared_ptr<StyleTemplate> forestStyle = boost::make_shared<StyleTemplate>();
266  highwayStyle->fill_color = boost::make_shared<eval::Eval<Color>>(Color((uint8)0x00, (uint8)0xaa, (uint8)0x00));
267  forestRule->setStyleTemplate(forestStyle);
268  forestRule->setAcceptableType(Rule::Accept_Way);
269 
270  rules.push_back(forestRule);
271 
272  shared_ptr<Rule> adminRule = boost::make_shared<Rule>(geodata);
273  shared_ptr<ApplySelector> adminApplier = boost::make_shared<ApplySelector>(adminRule);
274  shared_ptr<Selector> adminWaySelector = boost::make_shared<ChildWaysSelector>(adminRule, adminApplier);
275  shared_ptr<Selector> adminTagSelector = boost::make_shared<TagEqualsSelector>(adminRule, adminWaySelector, "boundary", "administrative");
276  adminRule->setFirstSelector(adminTagSelector);
277  shared_ptr<StyleTemplate> adminStyle = boost::make_shared<StyleTemplate>();
278  highwayStyle->fill_color = boost::make_shared<eval::Eval<Color>>(Color((uint8)0xaa, (uint8)0x00, (uint8)0x00));
279  highwayUpStyle->width = boost::make_shared<eval::Eval<float>>(2.0);
280  adminRule->setStyleTemplate(adminStyle);
281  adminRule->setAcceptableType(Rule::Accept_Relation);
282 
283  rules.push_back(adminRule);
284 
285 
286  return boost::make_shared<Stylesheet>(geodata, rules, canvasStyle);
287 }
288 
Thrown if no more time is left.
Definition: exceptions.hpp:87
std::uint8_t uint8
Definition: settings.hpp:112
TESTABLE bool hasStylesheet(const string &path)
boost::thread monitorThread
TESTABLE void onRemovedStylesheet(const fs::path &stylesheet_path)
removes the Stylesheet from the Stylesheet Cache and the prerendered tiles from the Cache...
TESTABLE void stopStylesheetObserving()
Stops the folder observation.
boost::scoped_ptr< boost::asio::dir_monitor > monitorService
TESTABLE void startStylesheetObserving(const shared_ptr< RequestManager > &manager)
starts observing the Stylesheet directory.
Thrown if the parsing fails.
Definition: exceptions.hpp:85
boost::shared_mutex stylesheetsLock
A TileIdentifier identifies a Tile.
static shared_ptr< Stylesheet > makeFallbackStylesheet(const shared_ptr< Geodata > &geodata)
TESTABLE void onFileSystemEvent(const boost::system::error_code &ec, const boost::asio::dir_monitor_event &ev)
handler method for dirwatch, forwards only .mapcss files to onNewStylesheet and onRemovedStylesheet ...
TESTABLE shared_ptr< Stylesheet > getStylesheet(const string &path)
Returns the Stylesheet Object for the Stylesheet specified.
std::string string
Definition: settings.hpp:110
#define LOG_SEV(log, lvl)
Definition: settings.hpp:78
static const char * style_source
Path to be observed for stylesheets (type: string)
shared_ptr< Configuration > config
TESTABLE void onNewStylesheet(const fs::path &stylesheet_path)
tries to read and parse the given file.
StylesheetManager(const shared_ptr< Configuration > &config)
Creates a new StylesheetManager with the given Configuration.
weak_ptr< RequestManager > manager
boost::asio::io_service ioService
Specifies the color.
Definition: mapcss_def.hpp:108
static const char * config
Option to get the configuration filename (type: string)
static const char * parse_timeout
Option to get the timeout for stylesheet-parsing (type: int)
static shared_ptr< Stylesheet > Load(const boost::filesystem::path &path, const shared_ptr< Geodata > &geodata, int timeout)
Parses the MapCSS Stylesheet at the given path and returns a new Stylesheet containing the defined ru...
boost::unordered_map< fs::path, shared_ptr< Stylesheet > > parsedStylesheets