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);
20 override public function loadBbox(left:Number,right:Number,
21 top:Number,bottom:Number):void {
22 var mapVars:URLVariables = new URLVariables();
23 mapVars.bbox= left+","+bottom+","+right+","+top;
25 var mapRequest:URLRequest = new URLRequest(Connection.apiBaseURL+"map");
26 mapRequest.data = mapVars;
28 var mapLoader:URLLoader = new URLLoader();
29 mapLoader.addEventListener(Event.COMPLETE, loadedMap);
30 mapLoader.load(mapRequest);
31 dispatchEvent(new Event(LOAD_STARTED));
34 private function parseTags(tagElements:XMLList):Object {
36 for each (var tagEl:XML in tagElements)
37 tags[tagEl.@k] = tagEl.@v;
41 private function loadedMap(event:Event):void {
42 dispatchEvent(new Event(LOAD_COMPLETED));
44 var map:XML = new XML(URLLoader(event.target).data);
49 for each(var nodeData:XML in map.node) {
50 id = Number(nodeData.@id);
51 version = uint(nodeData.@version);
53 var node:Node = getNode(id);
55 var lat:Number = Number(nodeData.@lat);
56 var lon:Number = Number(nodeData.@lon);
57 tags = parseTags(nodeData.tag);
58 setNode(new Node(id, version, tags, lat, lon));
62 for each(var data:XML in map.way) {
63 id = Number(data.@id);
64 version = uint(data.@version);
66 var way:Way = getWay(id);
69 for each(var nd:XML in data.nd)
70 nodes.push(getNode(Number(nd.@ref)));
71 tags = parseTags(data.tag);
72 setWay(new Way(id, version, tags, nodes));
77 protected var appID:OAuthConsumer;
78 protected var authToken:OAuthToken;
80 override public function setAppID(id:Object):void {
81 appID = OAuthConsumer(id);
84 override public function setAuthToken(id:Object):void {
85 authToken = OAuthToken(id);
88 private var httpStatus:int = 0;
90 private function recordStatus(event:HTTPStatusEvent):void {
91 httpStatus = event.status;
94 private var lastUploadedChangesetTags:Object;
96 override public function createChangeset(tags:Object):void {
97 lastUploadedChangesetTags = tags;
99 var changesetXML:XML = <osm version="0.6"><changeset /></osm>;
100 var changeset:XML = <changeset />;
101 for (var tagKey:Object in tags) {
102 var tagXML:XML = <tag/>;
104 tagXML.@v = tags[tagKey];
105 changesetXML.changeset.appendChild(tagXML);
108 // make an OAuth query
109 var sig:IOAuthSignatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
110 var url:String = Connection.apiBaseURL+"changeset/create";
111 var params:Object = { _method: "PUT" };
112 var oauthRequest:OAuthRequest = new OAuthRequest("POST", url, params, appID, authToken);
113 var urlStr:Object = oauthRequest.buildRequest(sig, OAuthRequest.RESULT_TYPE_URL_STRING)
115 // build the actual request
116 var urlReq:URLRequest = new URLRequest(String(urlStr));
117 urlReq.method = "POST";
118 urlReq.data = changesetXML.toXMLString();
119 urlReq.contentType = "application/xml";
120 var loader:URLLoader = new URLLoader();
121 loader.addEventListener(Event.COMPLETE, changesetCreateComplete);
122 loader.addEventListener(IOErrorEvent.IO_ERROR, changesetCreateError);
123 loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, recordStatus);
127 private function changesetCreateComplete(event:Event):void {
128 // response should be a Number changeset id
129 var id:Number = Number(URLLoader(event.target).data);
131 // which means we now have a new changeset!
132 setActiveChangeset(new Changeset(id, lastUploadedChangesetTags));
135 private function changesetCreateError(event:IOErrorEvent):void {
136 dispatchEvent(new Event(NEW_CHANGESET_ERROR));
139 override public function uploadChanges():void {
140 var changeset:Changeset = getActiveChangeset();
141 var upload:XML = <osmChange version="0.6"/>
142 upload.appendChild(addCreated(changeset, getAllNodeIDs, getNode, serialiseNode));
143 upload.appendChild(addCreated(changeset, getAllWayIDs, getWay, serialiseWay));
144 upload.appendChild(addCreated(changeset, getAllRelationIDs, getRelation, serialiseRelation));
145 upload.appendChild(addModified(changeset, getAllNodeIDs, getNode, serialiseNode));
146 upload.appendChild(addModified(changeset, getAllWayIDs, getWay, serialiseWay));
147 upload.appendChild(addModified(changeset, getAllRelationIDs, getRelation, serialiseRelation));
149 // *** TODO *** deleting items
151 // now actually upload them
152 // make an OAuth query
153 var sig:IOAuthSignatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
154 var url:String = Connection.apiBaseURL+"changeset/" + changeset.id + "/upload";
155 var oauthRequest:OAuthRequest = new OAuthRequest("POST", url, null, appID, authToken);
156 var urlStr:Object = oauthRequest.buildRequest(sig, OAuthRequest.RESULT_TYPE_URL_STRING)
158 // build the actual request
159 var urlReq:URLRequest = new URLRequest(String(urlStr));
160 urlReq.method = "POST";
161 urlReq.data = upload.toXMLString();
162 urlReq.contentType = "text/xml";
163 var loader:URLLoader = new URLLoader();
164 loader.addEventListener(Event.COMPLETE, diffUploadComplete);
165 loader.addEventListener(IOErrorEvent.IO_ERROR, diffUploadError);
166 loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, recordStatus);
169 dispatchEvent(new Event(SAVE_STARTED));
172 private function diffUploadComplete(event:Event):void {
173 // response should be XML describing the progress
174 var results:XML = new XML((URLLoader(event.target).data));
176 for each( var update:XML in results.child("*") ) {
177 var oldID:Number = Number(update.@old_id);
178 var newID:Number = Number(update.@new_id);
179 var version:uint = uint(update.@new_version);
180 var type:String = update.name();
183 if ( type == "node" ) entity = getNode(oldID);
184 else if ( type == "way" ) entity = getWay(oldID);
185 else if ( type == "relation" ) entity = getRelation(oldID);
186 entity.markClean(newID, version);
188 // *** TODO *** handle renumbering of creates, and deleting
191 dispatchEvent(new SaveCompleteEvent(SAVE_COMPLETED, true));
194 private function diffUploadError(event:IOErrorEvent):void {
195 trace("error "+URLLoader(event.target).data + " "+httpStatus+ " " + event.text);
197 dispatchEvent(new SaveCompleteEvent(SAVE_COMPLETED, false));
200 private function addCreated(changeset:Changeset, getIDs:Function, get:Function, serialise:Function):XML {
201 var create:XML = <create version="0.6"/>
202 for each( var id:Number in getIDs() ) {
206 var entity:Object = get(id);
207 var xml:XML = serialise(entity);
208 xml.@changeset = changeset.id;
209 create.appendChild(xml);
211 return create.hasComplexContent() ? create : <!-- blank create section -->;
214 private function addModified(changeset:Changeset, getIDs:Function, get:Function, serialise:Function):XML {
215 var modify:XML = <modify version="0.6"/>
216 for each( var id:Number in getIDs() ) {
217 var entity:Entity = get(id);
218 // creates are already included
219 if ( id < 0 || !entity.isDirty )
222 var xml:XML = serialise(entity);
223 xml.@changeset = changeset.id;
224 modify.appendChild(xml);
226 return modify.hasComplexContent() ? modify : <!-- blank modify section -->;
229 private function serialiseNode(node:Node):XML {
230 var xml:XML = <node/>
231 serialiseEntity(node, xml);
237 private function serialiseWay(way:Way):XML {
239 serialiseEntity(way, xml);
240 for ( var i:uint = 0; i < way.length; i++ ) {
242 nd.@ref = way.getNode(i).id;
248 private function serialiseRelation(relation:Relation):XML {
249 var xml:XML = <relation/>
250 serialiseEntity(relation, xml);
251 for ( var i:uint = 0; i < relation.length; i++ ) {
252 var relMember:RelationMember = relation.getMember(i);
253 var member:XML = <member/>
254 member.@ref = relMember.entity.id;
255 member.@type = relMember.entity.getType();
256 member.@role = relMember.role;
257 xml.appendChild(member);
262 private function serialiseEntity(entity:Entity, xml:XML):void {
264 xml.@version = entity.version;
265 for each( var tag:Tag in entity.getTagArray() ) {
266 var tagXML:XML = <tag/>
268 tagXML.@v = tag.value;
269 xml.appendChild(tagXML);