1 package net.systemeD.halcyon.connection {
5 import flash.system.Security;
7 import org.iotashan.oauth.*;
10 public class XMLConnection extends Connection {
12 //public var readConnection:NetConnection;
14 public function XMLConnection() {
16 if (Connection.policyURL!='')
17 Security.loadPolicyFile(Connection.policyURL);
18 var oauthPolicy:String = Connection.getParam("oauth_policy", "");
19 if ( oauthPolicy != "" ) {
21 Security.loadPolicyFile(oauthPolicy);
25 override public function loadBbox(left:Number,right:Number,
26 top:Number,bottom:Number):void {
27 var mapVars:URLVariables = new URLVariables();
28 mapVars.bbox= left+","+bottom+","+right+","+top;
30 var mapRequest:URLRequest = new URLRequest(Connection.apiBaseURL+"map");
31 mapRequest.data = mapVars;
33 var mapLoader:URLLoader = new URLLoader();
34 mapLoader.addEventListener(Event.COMPLETE, loadedMap);
35 mapLoader.addEventListener(IOErrorEvent.IO_ERROR, errorOnMapLoad);
36 mapLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, mapLoadStatus);
37 mapLoader.load(mapRequest);
38 dispatchEvent(new Event(LOAD_STARTED));
41 private function parseTags(tagElements:XMLList):Object {
43 for each (var tagEl:XML in tagElements)
44 tags[tagEl.@k] = tagEl.@v;
48 private function errorOnMapLoad(event:Event):void {
49 trace("error loading map");
51 private function mapLoadStatus(event:HTTPStatusEvent):void {
52 trace("loading map status = "+event.status);
55 private function loadedMap(event:Event):void {
56 dispatchEvent(new Event(LOAD_COMPLETED));
58 var map:XML = new XML(URLLoader(event.target).data);
63 for each(var nodeData:XML in map.node) {
64 id = Number(nodeData.@id);
65 version = uint(nodeData.@version);
67 var node:Node = getNode(id);
68 if ( node == null || !node.loaded ) {
69 var lat:Number = Number(nodeData.@lat);
70 var lon:Number = Number(nodeData.@lon);
71 tags = parseTags(nodeData.tag);
73 setNode(new Node(id, version, tags, true, lat, lon),false);
75 node.update(version, tags, true, lat, lon);
76 sendEvent(new EntityEvent(NEW_NODE, node), false);
81 for each(var data:XML in map.way) {
82 id = Number(data.@id);
83 version = uint(data.@version);
85 var way:Way = getWay(id);
86 if ( way == null || !way.loaded ) {
88 for each(var nd:XML in data.nd)
89 nodes.push(getNode(Number(nd.@ref)));
90 tags = parseTags(data.tag);
92 setWay(new Way(id, version, tags, true, nodes),false);
94 way.update(version, tags, true, nodes);
95 sendEvent(new EntityEvent(NEW_WAY, way), false);
100 for each(var relData:XML in map.relation) {
101 id = Number(relData.@id);
102 version = uint(relData.@version);
104 var rel:Relation = getRelation(id);
105 if ( rel == null || !rel.loaded ) {
106 tags = parseTags(relData.tag);
107 var members:Array = [];
108 for each(var memberXML:XML in relData.member) {
109 var type:String = memberXML.@type.toLowerCase();
110 var role:String = memberXML.@role;
111 var memberID:Number = Number(memberXML.@ref);
112 var member:Entity = null;
113 if ( type == "node" ) {
114 member = getNode(memberID);
115 if ( member == null ) {
116 member = new Node(memberID,0,{},false,0,0);
117 setNode(Node(member),true);
119 } else if ( type == "way" ) {
120 member = getWay(memberID);
121 if (member == null) {
122 member = new Way(memberID,0,{},false,[]);
123 setWay(Way(member),true);
125 } else if ( type == "relation" ) {
126 member = getRelation(memberID);
127 if (member == null) {
128 member = new Relation(memberID,0,{},false,[]);
129 setRelation(Relation(member),true);
133 if ( member != null )
134 members.push(new RelationMember(member, role));
138 setRelation(new Relation(id, version, tags, true, members), false);
140 rel.update(version,tags,true,members);
141 sendEvent(new EntityEvent(NEW_RELATION, rel), false);
149 protected function registerPOINodes():void {
150 for each (var nodeID:Number in getAllNodeIDs()) {
151 var node:Node = getNode(nodeID);
152 if (!node.hasParentWays)
157 protected var appID:OAuthConsumer;
158 protected var authToken:OAuthToken;
160 override public function setAppID(id:Object):void {
161 appID = OAuthConsumer(id);
164 override public function setAuthToken(id:Object):void {
165 authToken = OAuthToken(id);
168 private var httpStatus:int = 0;
170 private function recordStatus(event:HTTPStatusEvent):void {
171 httpStatus = event.status;
174 private var lastUploadedChangesetTags:Object;
176 override public function createChangeset(tags:Object):void {
177 lastUploadedChangesetTags = tags;
179 var changesetXML:XML = <osm version="0.6"><changeset /></osm>;
180 var changeset:XML = <changeset />;
181 for (var tagKey:Object in tags) {
182 var tagXML:XML = <tag/>;
184 tagXML.@v = tags[tagKey];
185 changesetXML.changeset.appendChild(tagXML);
188 // make an OAuth query
189 var sig:IOAuthSignatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
190 var url:String = Connection.apiBaseURL+"changeset/create";
191 //var params:Object = { _method: "PUT" };
192 var oauthRequest:OAuthRequest = new OAuthRequest("PUT", url, null, appID, authToken);
193 var urlStr:Object = oauthRequest.buildRequest(sig, OAuthRequest.RESULT_TYPE_URL_STRING)
195 // build the actual request
196 var urlReq:URLRequest = new URLRequest(String(urlStr));
197 urlReq.method = "POST";
198 urlReq.data = changesetXML.toXMLString();
199 urlReq.contentType = "application/xml";
200 urlReq.requestHeaders = new Array(new URLRequestHeader("X_HTTP_METHOD_OVERRIDE", "PUT"));
201 var loader:URLLoader = new URLLoader();
202 loader.addEventListener(Event.COMPLETE, changesetCreateComplete);
203 loader.addEventListener(IOErrorEvent.IO_ERROR, changesetCreateError);
204 loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, recordStatus);
208 private function changesetCreateComplete(event:Event):void {
209 // response should be a Number changeset id
210 var id:Number = Number(URLLoader(event.target).data);
212 // which means we now have a new changeset!
213 setActiveChangeset(new Changeset(id, lastUploadedChangesetTags));
216 private function changesetCreateError(event:IOErrorEvent):void {
217 dispatchEvent(new Event(NEW_CHANGESET_ERROR));
220 override public function uploadChanges():void {
221 var changeset:Changeset = getActiveChangeset();
222 var upload:XML = <osmChange version="0.6"/>
223 upload.appendChild(addCreated(changeset, getAllNodeIDs, getNode, serialiseNode));
224 upload.appendChild(addCreated(changeset, getAllWayIDs, getWay, serialiseWay));
225 upload.appendChild(addCreated(changeset, getAllRelationIDs, getRelation, serialiseRelation));
226 upload.appendChild(addModified(changeset, getAllNodeIDs, getNode, serialiseNode));
227 upload.appendChild(addModified(changeset, getAllWayIDs, getWay, serialiseWay));
228 upload.appendChild(addModified(changeset, getAllRelationIDs, getRelation, serialiseRelation));
230 // *** TODO *** deleting items
232 // now actually upload them
233 // make an OAuth query
234 var sig:IOAuthSignatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
235 var url:String = Connection.apiBaseURL+"changeset/" + changeset.id + "/upload";
236 var oauthRequest:OAuthRequest = new OAuthRequest("POST", url, null, appID, authToken);
237 var urlStr:Object = oauthRequest.buildRequest(sig, OAuthRequest.RESULT_TYPE_URL_STRING)
239 // build the actual request
240 var urlReq:URLRequest = new URLRequest(String(urlStr));
241 urlReq.method = "POST";
242 urlReq.data = upload.toXMLString();
243 urlReq.contentType = "text/xml";
244 var loader:URLLoader = new URLLoader();
245 loader.addEventListener(Event.COMPLETE, diffUploadComplete);
246 loader.addEventListener(IOErrorEvent.IO_ERROR, diffUploadError);
247 loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, recordStatus);
250 dispatchEvent(new Event(SAVE_STARTED));
253 private function diffUploadComplete(event:Event):void {
254 // response should be XML describing the progress
255 var results:XML = new XML((URLLoader(event.target).data));
257 for each( var update:XML in results.child("*") ) {
258 var oldID:Number = Number(update.@old_id);
259 var newID:Number = Number(update.@new_id);
260 var version:uint = uint(update.@new_version);
261 var type:String = update.name();
264 if ( type == "node" ) entity = getNode(oldID);
265 else if ( type == "way" ) entity = getWay(oldID);
266 else if ( type == "relation" ) entity = getRelation(oldID);
267 entity.markClean(newID, version);
269 if ( oldID != newID ) {
270 if ( type == "node" ) renumberNode(oldID, entity as Node);
271 else if ( type == "way" ) renumberWay(oldID, entity as Way);
272 else if ( type == "relation" ) renumberRelation(oldID, entity as Relation);
274 // *** TODO *** handle deleting
277 dispatchEvent(new SaveCompleteEvent(SAVE_COMPLETED, true));
280 private function diffUploadError(event:IOErrorEvent):void {
281 trace("error "+URLLoader(event.target).data + " "+httpStatus+ " " + event.text);
283 dispatchEvent(new SaveCompleteEvent(SAVE_COMPLETED, false));
286 private function addCreated(changeset:Changeset, getIDs:Function, get:Function, serialise:Function):XML {
287 var create:XML = <create version="0.6"/>
288 for each( var id:Number in getIDs() ) {
292 var entity:Object = get(id);
293 var xml:XML = serialise(entity);
294 xml.@changeset = changeset.id;
295 create.appendChild(xml);
297 return create.hasComplexContent() ? create : <!-- blank create section -->;
300 private function addModified(changeset:Changeset, getIDs:Function, get:Function, serialise:Function):XML {
301 var modify:XML = <modify version="0.6"/>
302 for each( var id:Number in getIDs() ) {
303 var entity:Entity = get(id);
304 // creates are already included
305 if ( id < 0 || !entity.isDirty )
308 var xml:XML = serialise(entity);
309 xml.@changeset = changeset.id;
310 modify.appendChild(xml);
312 return modify.hasComplexContent() ? modify : <!-- blank modify section -->;
315 private function serialiseNode(node:Node):XML {
316 var xml:XML = <node/>
317 serialiseEntity(node, xml);
323 private function serialiseWay(way:Way):XML {
325 serialiseEntity(way, xml);
326 for ( var i:uint = 0; i < way.length; i++ ) {
328 nd.@ref = way.getNode(i).id;
334 private function serialiseRelation(relation:Relation):XML {
335 var xml:XML = <relation/>
336 serialiseEntity(relation, xml);
337 for ( var i:uint = 0; i < relation.length; i++ ) {
338 var relMember:RelationMember = relation.getMember(i);
339 var member:XML = <member/>
340 member.@ref = relMember.entity.id;
341 member.@type = relMember.entity.getType();
342 member.@role = relMember.role;
343 xml.appendChild(member);
348 private function serialiseEntity(entity:Entity, xml:XML):void {
350 xml.@version = entity.version;
351 for each( var tag:Tag in entity.getTagArray() ) {
352 var tagXML:XML = <tag/>
354 tagXML.@v = tag.value;
355 xml.appendChild(tagXML);