| 28283f5 by James Michael DuPont at 2010-03-13 |
1 |
package com.cloudmade.mappingtool.model;
|
|
2 |
|
|
3 |
import com.cloudmade.mappingtool.business.externalization.IXMLListSerializer;
|
|
4 |
import com.cloudmade.mappingtool.business.externalization.IXMLSerializer;
|
|
5 |
import com.cloudmade.mappingtool.business.externalization.osm.ListExternalizer;
|
|
6 |
import com.cloudmade.mappingtool.business.externalization.osm.TagExternalizer;
|
|
7 |
import com.cloudmade.mappingtool.business.externalization.osm.ValidTagsSerializer;
|
|
8 |
import com.cloudmade.mappingtool.events.OSMProxyCommitErrorEvent;
|
|
9 |
import com.cloudmade.mappingtool.events.OSMProxyLoadErrorEvent;
|
|
10 |
import com.cloudmade.mappingtool.events.OSMProxyResultEvent;
|
|
11 |
import com.cloudmade.mappingtool.events.OSMProxySaveEvent;
|
|
12 |
import com.cloudmade.mappingtool.map.geo.LatLong;
|
|
13 |
import com.cloudmade.mappingtool.map.geo.LatLongBounds;
|
|
14 |
import com.cloudmade.mappingtool.map.model.Member;
|
|
15 |
import com.cloudmade.mappingtool.map.model.Node;
|
|
16 |
import com.cloudmade.mappingtool.map.model.Relation;
|
|
17 |
import com.cloudmade.mappingtool.map.model.Tag;
|
|
18 |
import com.cloudmade.mappingtool.map.model.Way;
|
|
19 |
import com.cloudmade.mappingtool.model.osm.ElementDiff;
|
|
20 |
import com.cloudmade.mappingtool.model.osm.OAuthAuthorizator;
|
|
21 |
import com.cloudmade.mappingtool.model.osm.Transaction;
|
|
22 |
import com.cloudmade.mappingtool.model.osm.TransactionQueue;
|
|
23 |
|
|
24 |
import flash.errors.IOError;
|
|
25 |
import flash.events.ErrorEvent;
|
|
26 |
import flash.events.Event;
|
|
27 |
import flash.events.EventDispatcher;
|
|
28 |
import flash.events.HTTPStatusEvent;
|
|
29 |
import flash.events.IOErrorEvent;
|
|
30 |
import flash.events.SecurityErrorEvent;
|
|
31 |
import flash.net.URLLoader;
|
|
32 |
import flash.net.URLRequest;
|
|
33 |
import flash.system.Security;
|
|
34 |
import flash.utils.ByteArray;
|
|
35 |
|
|
36 |
import mx.managers.CursorManager;
|
|
37 |
|
|
38 |
/*[Event(name="save", type="com.cloudmade.mappingtool.events.OSMProxyResultEvent")]*/
|
|
39 |
/*[Event(name="result", type="com.cloudmade.mappingtool.events.OSMProxyResultEvent")]*/
|
|
40 |
/*[Event(name="saveFailed", type="com.cloudmade.mappingtool.events.OSMProxySaveEvent")]*/
|
|
41 |
/*[Event(name="saveComplete", type="com.cloudmade.mappingtool.events.OSMProxySaveEvent")]*/
|
|
42 |
/*[Event(name="loadError", type="com.cloudmade.mappingtool.events.OSMProxyLoadErrorEvent")]*/
|
|
43 |
/*[Event(name="commitError", type="com.cloudmade.mappingtool.events.OSMProxyCommitErrorEvent")]*/
|
|
44 |
/*[Event(name="loadingChanged", type="flash.events.Event")]*/
|
|
45 |
|
|
46 |
// TODO: Use polymorphism.
|
|
47 |
|
|
48 |
public final class OSMProxy extends EventDispatcher {
|
|
49 |
|
|
50 |
public var changesetOpened(getChangesetOpened, null) : Bool ;
|
|
51 |
public var loading(getLoading, null) : Bool ;
|
|
52 |
/*[Embed(source="../../../../config/map.xml", mimeType="application/octet-stream")]*/
|
|
53 |
CONFIG::local
|
|
54 |
static var LOCAL_MAP:Class<Dynamic>;
|
|
55 |
|
|
56 |
static var instance:OSMProxy = null;
|
|
57 |
|
|
58 |
public static function getInstance():OSMProxy {
|
|
59 |
if (instance == null) {
|
|
60 |
instance = new OSMProxy(new SingletonEnforcer());
|
|
61 |
}
|
|
62 |
return instance;
|
|
63 |
}
|
|
64 |
|
|
65 |
CONFIG::public debug
|
|
66 |
var errorModeEnabled:Bool ;
|
|
67 |
|
|
68 |
var nodeMap:Dynamic;
|
|
69 |
var changesetId:String;
|
|
70 |
var lastHttpStatus:Int;
|
|
71 |
var createdWays:Array<Dynamic> ;
|
|
72 |
var modifiedWays:Array<Dynamic> ;
|
|
73 |
var deletedWays:Array<Dynamic> ;
|
|
74 |
var createdNodes:Array<Dynamic> ;
|
|
75 |
var modifiedNodes:Array<Dynamic> ;
|
|
76 |
var deletedNodes:Array<Dynamic> ;
|
|
77 |
var modifiedRelations:Array<Dynamic> ;
|
|
78 |
var mapLoader:URLLoader ;
|
|
79 |
var authorizator:OAuthAuthorizator ;
|
|
80 |
var openTransaction:Transaction (authorizator, true, CONFIG::osm + "changeset/create");
|
|
81 |
var closeTransaction:Transaction (authorizator, true, CONFIG::osm + "changeset/");
|
|
82 |
var commitTransaction:Transaction (authorizator, false, CONFIG::osm + "changeset/");
|
|
83 |
var transactionQueue:TransactionQueue ;
|
|
84 |
|
|
85 |
var tagsSerializer:IXMLListSerializer;
|
|
86 |
|
|
87 |
public function new(enforcer:SingletonEnforcer) {
|
|
88 |
|
|
89 |
errorModeEnabled = false;
|
|
90 |
createdWays = new Array();
|
|
91 |
modifiedWays = new Array();
|
|
92 |
deletedWays = new Array();
|
|
93 |
createdNodes = new Array();
|
|
94 |
modifiedNodes = new Array();
|
|
95 |
deletedNodes = new Array();
|
|
96 |
modifiedRelations = new Array();
|
|
97 |
mapLoader = new URLLoader();
|
|
98 |
authorizator = new OAuthAuthorizator();
|
|
99 |
openTransaction = new Transaction;
|
|
100 |
closeTransaction = new Transaction;
|
|
101 |
commitTransaction = new Transaction;
|
|
102 |
transactionQueue = new TransactionQueue();
|
|
103 |
super();
|
|
104 |
Security.loadPolicyFile(CONFIG::crossdomain);
|
|
105 |
transactionQueue.addTransaction(openTransaction);
|
|
106 |
transactionQueue.addTransaction(commitTransaction);
|
|
107 |
transactionQueue.addTransaction(closeTransaction);
|
|
108 |
mapLoader.addEventListener(Event.COMPLETE, mapLoader_completeHandler);
|
|
109 |
mapLoader.addEventListener(IOErrorEvent.IO_ERROR, mapLoader_errorHandler);
|
|
110 |
mapLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, mapLoader_errorHandler);
|
|
111 |
transactionQueue.addEventListener(Event.COMPLETE, transactionQueue_completeHandler);
|
|
112 |
transactionQueue.addEventListener(IOErrorEvent.IO_ERROR, transactionQueue_ioErrorHandler);
|
|
113 |
commitTransaction.addEventListener(IOErrorEvent.IO_ERROR, commitTransaction_ioErrorHandler);
|
|
114 |
transactionQueue.addEventListener(HTTPStatusEvent.HTTP_STATUS, transactionQueue_httpStatusHandler);
|
|
115 |
openTransaction.addEventListener(Event.COMPLETE, openTransaction_completeHandler, false, 1);
|
|
116 |
|
|
117 |
tagsSerializer = createTagsSerializer();
|
|
118 |
}
|
|
119 |
|
|
120 |
var _changesetOpened:Bool;
|
|
121 |
public function getChangesetOpened():Bool {
|
|
122 |
return _changesetOpened;
|
|
123 |
}
|
|
124 |
|
|
125 |
var _loading:Bool ;
|
|
126 |
|
|
127 |
/*[Bindable("loadingChanged")]*/
|
|
128 |
public function getLoading():Bool {
|
|
129 |
return _loading;
|
|
130 |
}
|
|
131 |
|
|
132 |
public function getMap(bounds:LatLongBounds):Void {
|
|
133 |
CONFIG::local {
|
|
134 |
var bytes:ByteArray = new LOCAL_MAP();
|
|
135 |
mapLoader.data = bytes.toString();
|
|
136 |
mapLoader_completeHandler(null);
|
|
137 |
return;
|
|
138 |
}
|
|
139 |
setLoading(true);
|
|
140 |
var boundsArray:Array<Dynamic> = [bounds.westLong, bounds.southLat, bounds.eastLong, bounds.northLat];
|
|
141 |
var url:String = CONFIG::osm + "map?bbox=" + boundsArray.join(",");
|
|
142 |
mapLoader.load(new URLRequest(url));
|
|
143 |
}
|
|
144 |
|
|
145 |
public function close():Void {
|
|
146 |
try {
|
|
147 |
mapLoader.close();
|
|
148 |
} catch (error:IOError) {
|
|
149 |
}
|
|
150 |
setLoading(false);
|
|
151 |
}
|
|
152 |
|
|
153 |
public function setCredentials(username:String, password:String):Void {
|
|
154 |
transactionQueue.setCredentials(username, password);
|
|
155 |
}
|
|
156 |
|
|
157 |
public function openChangeset(tags:Array<Dynamic>):Void {
|
|
158 |
if (!_changesetOpened) {
|
|
159 |
_changesetOpened = true;
|
|
160 |
var xml:XML = Xml.parse("<changeset></changeset>");
|
|
161 |
serializeTags(xml, tags);
|
|
162 |
openTransaction.requestData = "<osm>" + xml.toXMLString() + "</osm>";
|
|
163 |
}
|
|
164 |
}
|
|
165 |
|
|
166 |
public function createNode(node:Node):Void {
|
|
167 |
createdNodes.push(node);
|
|
168 |
}
|
|
169 |
|
|
170 |
public function modifyNode(node:Node):Void {
|
|
171 |
modifiedNodes.push(node);
|
|
172 |
}
|
|
173 |
|
|
174 |
public function deleteNode(node:Node):Void {
|
|
175 |
deletedNodes.push(node);
|
|
176 |
}
|
|
177 |
|
|
178 |
public function createWay(way:Way):Void {
|
|
179 |
createdWays.push(way);
|
|
180 |
}
|
|
181 |
|
|
182 |
public function modifyWay(way:Way):Void {
|
|
183 |
modifiedWays.push(way);
|
|
184 |
}
|
|
185 |
|
|
186 |
public function deleteWay(way:Way):Void {
|
|
187 |
deletedWays.push(way);
|
|
188 |
}
|
|
189 |
|
|
190 |
public function modifyRelation(relation:Relation):Void {
|
|
191 |
modifiedRelations.push(relation);
|
|
192 |
}
|
|
193 |
|
|
194 |
public function closeChangeset():Void {
|
|
195 |
if (_changesetOpened) {
|
|
196 |
lastHttpStatus = 0;
|
|
197 |
transactionQueue.send();
|
|
198 |
}
|
|
199 |
}
|
|
200 |
|
|
201 |
function serializeNodes(xml:XML, nodes:Array<Dynamic>):Void {
|
|
202 |
for (node in nodes) {
|
|
203 |
var nodeXml:XML = Xml.parse("<node></node>");
|
|
204 |
nodeXml.@id = node.id;
|
|
205 |
nodeXml.@version = node.version;
|
|
206 |
nodeXml.@lat = node.position.lat;
|
|
207 |
nodeXml.@lon = node.position.long;
|
|
208 |
nodeXml.@changeset = changesetId;
|
|
209 |
serializeTags(nodeXml, node.tags.source);
|
|
210 |
xml.appendChild(nodeXml);
|
|
211 |
}
|
|
212 |
}
|
|
213 |
|
|
214 |
function serializeWays(xml:XML, ways:Array<Dynamic>):Void {
|
|
215 |
for (way in ways) {
|
|
216 |
var wayXml:XML = Xml.parse("<way></way>");
|
|
217 |
wayXml.@id = way.id;
|
|
218 |
wayXml.@version = way.version;
|
|
219 |
wayXml.@changeset = changesetId;
|
|
220 |
var nodes:Array<Dynamic> = way.nodes.source;
|
|
221 |
for (node in nodes) {
|
|
222 |
wayXml.appendChild(Xml.parse("<nd ref={node.id}/>"));
|
|
223 |
}
|
|
224 |
serializeTags(wayXml, way.tags.source);
|
|
225 |
xml.appendChild(wayXml);
|
|
226 |
}
|
|
227 |
}
|
|
228 |
|
|
229 |
function serializeRelations(xml:XML, relations:Array<Dynamic>):Void {
|
|
230 |
for (relation in relations) {
|
|
231 |
var relationXml:XML = Xml.parse("<relation></relation>");
|
|
232 |
relationXml.@id = relation.id;
|
|
233 |
relationXml.@version = relation.version;
|
|
234 |
relationXml.@changeset = changesetId;
|
|
235 |
serializeMembers(relationXml, relation.members.source);
|
|
236 |
serializeTags(relationXml, relation.tags.source);
|
|
237 |
xml.appendChild(relationXml);
|
|
238 |
}
|
|
239 |
}
|
|
240 |
|
|
241 |
function serializeMembers(xml:XML, members:Array<Dynamic>):Void {
|
|
242 |
for (member in members) {
|
|
243 |
var memberXml:XML = Xml.parse("<member/>");
|
|
244 |
memberXml.@type = member.type;
|
|
245 |
memberXml.@ref = member.elementId;
|
|
246 |
memberXml.@role = member.role;
|
|
247 |
xml.appendChild(memberXml);
|
|
248 |
}
|
|
249 |
}
|
|
250 |
|
|
251 |
function serializeTags(xml:XML, tags:Array<Dynamic>):Void {
|
|
252 |
var tagsXml:XMLList = tagsSerializer.serialize(tags);
|
|
253 |
for (tagXml in tagsXml) {
|
|
254 |
xml.appendChild(tagXml);
|
|
255 |
}
|
|
256 |
}
|
|
257 |
|
|
258 |
function createTagsSerializer():IXMLListSerializer {
|
|
259 |
var tagSerializer:IXMLSerializer = new TagExternalizer();
|
|
260 |
var tagsSerializer:IXMLListSerializer = new ListExternalizer(tagSerializer, null);
|
|
261 |
return new ValidTagsSerializer(tagsSerializer);
|
|
262 |
}
|
|
263 |
|
|
264 |
function deserializeNodes(xml:XMLList):Array<Dynamic> {
|
|
265 |
var nodes:Array<Dynamic> = new Array();
|
|
266 |
var node:Node;
|
|
267 |
xml.(
|
|
268 |
node = new Node(@id, deserializeTags(elements("tag")), new LatLong(@lat, @lon)),
|
|
269 |
node.version = @version,
|
|
270 |
nodes.push(node)
|
|
271 |
);
|
|
272 |
return nodes;
|
|
273 |
}
|
|
274 |
|
|
275 |
function deserializeWays(xml:XMLList):Array<Dynamic> {
|
|
276 |
var ways:Array<Dynamic> = new Array();
|
|
277 |
var nodes:Array<Dynamic>;
|
|
278 |
var way:Way;
|
|
279 |
xml.(
|
|
280 |
nodes = new Array(),
|
|
281 |
nd.(nodes.push(nodeMap[@ref])),
|
|
282 |
way = new Way(@id, deserializeTags(elements("tag")), nodes),
|
|
283 |
way.version = @version,
|
|
284 |
ways.push(way)
|
|
285 |
);
|
|
286 |
return ways;
|
|
287 |
}
|
|
288 |
|
|
289 |
function dererializeRelations(xml:XMLList):Array<Dynamic> {
|
|
290 |
var relations:Array<Dynamic> = new Array();
|
|
291 |
var members:Array<Dynamic>;
|
|
292 |
var relation:Relation;
|
|
293 |
xml.(
|
|
294 |
members = deserializeRelationMembers(elements("member")),
|
|
295 |
relation = new Relation(@id, deserializeTags(elements("tag")), members),
|
|
296 |
relation.version = @version,
|
|
297 |
relations.push(relation)
|
|
298 |
);
|
|
299 |
return relations;
|
|
300 |
}
|
|
301 |
|
|
302 |
function deserializeTags(xml:XMLList):Array<Dynamic> {
|
|
303 |
var tags:Array<Dynamic> = new Array();
|
|
304 |
xml.(tags.push(new Tag(@k, @v)));
|
|
305 |
return tags;
|
|
306 |
}
|
|
307 |
|
|
308 |
function deserializeRelationMembers(xml:XMLList):Array<Dynamic> {
|
|
309 |
var members:Array<Dynamic> = new Array();
|
|
310 |
xml.(members.push(new Member(@ref, @type, @role)));
|
|
311 |
return members;
|
|
312 |
}
|
|
313 |
|
|
314 |
function deserializeDiffs(xml:XMLList):Array<Dynamic> {
|
|
315 |
var diffs:Array<Dynamic> = new Array();
|
|
316 |
// Parse create or modify, but not delete.
|
|
317 |
xml.(hasOwnProperty("@new_version")).
|
|
318 |
(diffs.push(new ElementDiff(@old_id, @new_id, @new_version)));
|
|
319 |
return diffs;
|
|
320 |
}
|
|
321 |
|
|
322 |
function setLoading(value:Bool):Void {
|
|
323 |
if (value == _loading) return;
|
|
324 |
_loading = value;
|
|
325 |
dispatchEvent(new Event("loadingChanged"));
|
|
326 |
/*if (value) {
|
|
327 |
CursorManager.setBusyCursor();
|
|
328 |
} else {
|
|
329 |
CursorManager.removeBusyCursor();
|
|
330 |
}*/
|
|
331 |
}
|
|
332 |
|
|
333 |
function endChangeset():Void {
|
|
334 |
createdWays = new Array();
|
|
335 |
modifiedWays = new Array();
|
|
336 |
deletedWays = new Array();
|
|
337 |
createdNodes = new Array();
|
|
338 |
modifiedNodes = new Array();
|
|
339 |
deletedNodes = new Array();
|
|
340 |
modifiedRelations = new Array();
|
|
341 |
_changesetOpened = false;
|
|
342 |
}
|
|
343 |
|
|
344 |
function mapLoader_completeHandler(event:Event):Void {
|
|
345 |
var xml:XML = new XML(mapLoader.data);
|
|
346 |
var nodes:Array<Dynamic> = deserializeNodes(xml.node);
|
|
347 |
nodeMap = new Object();
|
|
348 |
for (node in nodes) {
|
|
349 |
nodeMap[node.id] = node;
|
|
350 |
}
|
|
351 |
var ways:Array<Dynamic> = deserializeWays(xml.way);
|
|
352 |
var relations:Array<Dynamic> = dererializeRelations(xml.relation);
|
|
353 |
dispatchEvent(new OSMProxyResultEvent(OSMProxyResultEvent.RESULT, nodes, ways, relations));
|
|
354 |
setLoading(false);
|
|
355 |
}
|
|
356 |
|
|
357 |
function mapLoader_errorHandler(event:ErrorEvent):Void {
|
|
358 |
setLoading(false);
|
|
359 |
dispatchEvent(new OSMProxyLoadErrorEvent(OSMProxyLoadErrorEvent.LOAD_ERROR));
|
|
360 |
}
|
|
361 |
|
|
362 |
function openTransaction_completeHandler(event:Event):Void {
|
|
363 |
changesetId = String(openTransaction.data);
|
|
364 |
var xml:XML = new XML("<osmChange></osmChange>");
|
|
365 |
var createXml:XML = new XML("<create></create>");
|
|
366 |
serializeNodes(createXml, createdNodes);
|
|
367 |
serializeWays(createXml, createdWays);
|
|
368 |
xml.appendChild(createXml);
|
|
369 |
var modifyXml:XML = new XML("<modify></modify>");
|
|
370 |
serializeNodes(modifyXml, modifiedNodes);
|
|
371 |
serializeWays(modifyXml, modifiedWays);
|
|
372 |
serializeRelations(modifyXml, modifiedRelations);
|
|
373 |
xml.appendChild(modifyXml);
|
|
374 |
var deleteXml:XML = new XML("<delete></delete>");
|
|
375 |
serializeWays(deleteXml, deletedWays);
|
|
376 |
serializeNodes(deleteXml, deletedNodes);
|
|
377 |
xml.appendChild(deleteXml);
|
|
378 |
commitTransaction.requestData = xml.toXMLString();
|
|
379 |
commitTransaction.url = changesetId + "/upload";
|
|
380 |
closeTransaction.url = changesetId + "/close";
|
|
381 |
CONFIG::debug {
|
|
382 |
if (errorModeEnabled) {
|
|
383 |
commitTransaction.requestData = commitTransaction.requestData.substr(1);
|
|
384 |
}
|
|
385 |
}
|
|
386 |
}
|
|
387 |
|
|
388 |
function transactionQueue_completeHandler(event:Event):Void {
|
|
389 |
endChangeset();
|
|
390 |
var xml:XML = new XML(commitTransaction.data);
|
|
391 |
var nodeDiffs:Array<Dynamic> = deserializeDiffs(xml.node);
|
|
392 |
var wayDiffs:Array<Dynamic> = deserializeDiffs(xml.way);
|
|
393 |
var relationDiffs:Array<Dynamic> = deserializeDiffs(xml.relation);
|
|
394 |
dispatchEvent(new OSMProxySaveEvent(OSMProxySaveEvent.SAVE_COMPLETE, changesetId));
|
|
395 |
dispatchEvent(new OSMProxyResultEvent(OSMProxyResultEvent.SAVE, nodeDiffs, wayDiffs, relationDiffs));
|
|
396 |
}
|
|
397 |
|
|
398 |
function transactionQueue_ioErrorHandler(event:IOErrorEvent):Void {
|
|
399 |
endChangeset();
|
|
400 |
//Alert.show("httpStatus: " + lastHttpStatus);
|
|
401 |
dispatchEvent(new OSMProxySaveEvent(OSMProxySaveEvent.SAVE_FAILED));
|
|
402 |
}
|
|
403 |
|
|
404 |
function transactionQueue_httpStatusHandler(event:HTTPStatusEvent):Void {
|
|
405 |
lastHttpStatus = event.status;
|
|
406 |
}
|
|
407 |
|
| 11ab0d0 by James Michael DuPont at 2010-03-13 |
408 |
function commitTransaction_ioErrorHandler(event:IOErrorEvent):Void { |
| 2fc88c4 by James Michael DuPont at 2010-03-12 |
409 |
dispatchEvent(new OSMProxyCommitErrorEvent(OSMProxyCommitErrorEvent.COMMIT_ERROR, commitTransaction.requestData)); |
| 28283f5 by James Michael DuPont at 2010-03-13 |
410 |
}
|
|
411 |
}
|