Commit 99c713c04eb944562a94a79c3477d0e7fbb66f1b

Improving database cache performance.

Using externalization to improve serialization speed and to reduce data
size. Fixing bugs in the database cache implementation.
  
2222package eu.cdauth.osm.lib.api06;
2323
2424import eu.cdauth.osm.lib.*;
25import java.io.Externalizable;
26import java.io.IOException;
27import java.io.ObjectInput;
28import java.io.ObjectOutput;
2529import org.w3c.dom.Element;
2630import org.w3c.dom.NodeList;
2731
3737
3838public class API06Changeset extends API06Item implements Changeset
3939{
40 private Hashtable<ChangeType, VersionedItem[]> m_content = null;
40 private Map<ChangeType, VersionedItem[]> m_content = null;
4141
42 private Date m_creation = null;
43 private Date m_closing = null;
44 private User m_user = null;
45
46 @Override
47 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
48 {
49 super.readExternal(in);
50 m_content = (Map<ChangeType, VersionedItem[]>)in.readObject();
51 m_creation = (Date)in.readObject();
52 m_closing = (Date)in.readObject();
53 m_user = (User)in.readObject();
54 }
55
56 @Override
57 public void writeExternal(ObjectOutput out) throws IOException
58 {
59 super.writeExternal(out);
60 out.writeObject(m_content);
61 out.writeObject(m_creation);
62 out.writeObject(m_closing);
63 out.writeObject(m_user);
64 }
65
4266 /**
4367 * Contains the uncleaned osmChange XML element.
4468 */
45 private Element m_uncleanedDom = null;
69 private Element m_uncleanedDom = null; // FIXME: Do not serialize
4670
4771 /**
4872 * Only for serialization.
7979 protected API06Changeset(Element a_dom, API06API a_api)
8080 {
8181 super(a_dom, a_api);
82 }
8382
84 @Override
85 public Date getCreationDate()
86 {
8783 try
8884 {
89 return API06GeographicalItem.getDateFormat().parse(getDOM().getAttribute("created_at"));
85 m_creation = API06GeographicalItem.getDateFormat().parse(a_dom.getAttribute("created_at"));
9086 }
9187 catch(ParseException e)
9288 {
93 return null;
9489 }
95 }
9690
97 @Override
98 public Date getClosingDate()
99 {
10091 try
10192 {
102 return API06GeographicalItem.getDateFormat().parse(getDOM().getAttribute("closed_at"));
93 m_closing = API06GeographicalItem.getDateFormat().parse(a_dom.getAttribute("closed_at"));
10394 }
10495 catch(ParseException e)
10596 {
106 return null;
10797 }
98
99 m_user = new User(new ID(a_dom.getAttribute("uid")), a_dom.getAttribute("user"));
108100 }
109101
110102 @Override
103 public Date getCreationDate()
104 {
105 return m_creation;
106 }
107
108 @Override
109 public Date getClosingDate()
110 {
111 return m_closing;
112 }
113
114 @Override
111115 public User getUser()
112116 {
113 return new User(new ID(getDOM().getAttribute("uid")), getDOM().getAttribute("user"));
117 return m_user;
114118 }
115119
116120 /**
  
2323
2424import java.text.ParseException;
2525import java.text.SimpleDateFormat;
26import java.util.Collection;
2726import java.util.Date;
2827
2928import eu.cdauth.osm.lib.*;
3029import org.w3c.dom.Element;
3130
3231import eu.cdauth.osm.lib.GeographicalItem;
32import java.io.IOException;
33import java.io.ObjectInput;
34import java.io.ObjectOutput;
35import java.util.Arrays;
36import java.util.SimpleTimeZone;
3337
3438abstract public class API06GeographicalItem extends API06Item implements VersionedItem, GeographicalItem
3539{
36 private static SimpleDateFormat sm_dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
40 private static final SimpleDateFormat sm_dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
41 static {
42 sm_dateFormat.setTimeZone(new SimpleTimeZone(0, "UTC"));
43 }
3744
38 private boolean m_current = false;
45 private boolean m_current = false; // FIXME: Serialize?
3946
47 private Date m_timestamp = null;
48 private Version m_version = null;
49 private ID m_changeset = null;
4050 private ID[] m_containingRelations = null;
4151
52 @Override
53 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
54 {
55 super.readExternal(in);
56 m_current = in.readBoolean();
57 m_timestamp = (Date)in.readObject();
58 m_version = (Version)in.readObject();
59 m_changeset = (ID)in.readObject();
60 m_containingRelations = (ID[])in.readObject();
61 }
62
63 @Override
64 public void writeExternal(ObjectOutput out) throws IOException
65 {
66 super.writeExternal(out);
67 out.writeBoolean(m_current);
68 out.writeObject(m_timestamp);
69 out.writeObject(m_version);
70 out.writeObject(m_changeset);
71 out.writeObject(m_containingRelations);
72 }
73
4274 /**
4375 * Only for serialization.
4476 */
8787 protected API06GeographicalItem(Element a_dom, API06API a_api)
8888 {
8989 super(a_dom, a_api);
90
91 try
92 {
93 m_timestamp = getDateFormat().parse(a_dom.getAttribute("timestamp"));
94 }
95 catch(ParseException e)
96 {
97 }
98
99 String version = a_dom.getAttribute("version");
100 if(!version.equals(""))
101 m_version = new Version(version);
102
103 m_changeset = new ID(a_dom.getAttribute("changeset"));
90104 }
91105
92106 /**
123123 @Override
124124 public Date getTimestamp()
125125 {
126 try
127 {
128 return getDateFormat().parse(getDOM().getAttribute("timestamp"));
129 }
130 catch(ParseException e)
131 {
132 return null;
133 }
126 return m_timestamp;
134127 }
135128
136129 @Override
139139 @Override
140140 public Version getVersion()
141141 {
142 String version = getDOM().getAttribute("version");
143 if(version.equals(""))
144 return null;
145 return new Version(version);
142 return m_version;
146143 }
147144
148145 @Override
149146 public ID getChangeset()
150147 {
151 return new ID(getDOM().getAttribute("changeset"));
148 return m_changeset;
152149 }
153150
154151 @Override
155 public Relation[] getContainingRelations() throws APIError
152 public ID[] getContainingRelations() throws APIError
156153 {
157154 if(m_containingRelations == null)
158155 {
164164 throw new RuntimeException("Unknown data type.");
165165
166166 Item[] relations = getAPI().get("/"+urlPart+"/"+getID()+"/relations");
167 Relation[] ret = new Relation[relations.length];
168 for(int i=0; i<relations.length; i++)
169 ret[i] = (Relation)relations[i];
167 m_containingRelations = new ID[relations.length];
170168 VersionedItemCache<Relation> cache = getAPI().getRelationFactory().getCache();
171 for(Relation it : ret)
169 for(int i=0; i<relations.length; i++)
172170 {
173 ((API06Relation)it).markAsCurrent();
174 cache.cacheObject(it);
171 m_containingRelations[i] = relations[i].getID();
172 ((API06Relation)relations[i]).markAsCurrent();
173 cache.cacheObject((Relation)relations[i]);
175174 }
176
177 synchronized(this)
178 {// TODO This does not seem to be useful
179 m_containingRelations = new ID[ret.length];
180 for(int i=0; i<ret.length; i++)
181 m_containingRelations[i] = ret[i].getID();
182 }
183
184 return ret;
185175 }
186 else
187 {
188 Collection<Relation> ret = getAPI().getRelationFactory().fetch(m_containingRelations).values();
189 return ret.toArray(new Relation[ret.size()]);
190 }
176
177 return Arrays.copyOf(m_containingRelations, m_containingRelations.length);
191178 }
192179}
  
2121
2222package eu.cdauth.osm.lib.api06;
2323
24import eu.cdauth.osm.lib.Changeset;
25import java.io.IOException;
26import java.io.ObjectInput;
27import java.io.ObjectOutput;
2428import java.util.Hashtable;
2529import java.util.Map;
2630
3333import org.w3c.dom.NodeList;
3434
3535import eu.cdauth.osm.lib.ID;
36import eu.cdauth.osm.lib.Node;
37import eu.cdauth.osm.lib.Relation;
38import eu.cdauth.osm.lib.VersionedItem;
39import eu.cdauth.osm.lib.Way;
40import java.io.Externalizable;
41import java.util.Collections;
3642
3743/**
3844 * Parent class for all geographical objects in OSM, currently Nodes, Ways and Relations.
4646
4747abstract public class API06Item extends API06XMLItem implements Item
4848{
49 private Hashtable<String,String> m_tags = null;
49 private ID m_id = null;
50 private Map<String,String> m_tags = null;
5051
52 @Override
53 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
54 {
55 super.readExternal(in);
56 m_id = (ID)in.readObject();
57 m_tags = (Map<String,String>)in.readObject();
58 }
59
60 @Override
61 public void writeExternal(ObjectOutput out) throws IOException
62 {
63 super.writeExternal(out);
64 out.writeObject(m_id);
65 out.writeObject(m_tags);
66 }
67
5168 /**
5269 * Only for serialization.
5370 */
7676 protected API06Item(Element a_dom, API06API a_api)
7777 {
7878 super(a_dom, a_api);
79
80 m_id = new ID(a_dom.getAttribute("id"));
81
82 m_tags = new Hashtable<String,String>();
83 NodeList tags = a_dom.getElementsByTagName("tag");
84 for(int i=0; i<tags.getLength(); i++)
85 {
86 if(tags.item(i).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE)
87 continue;
88 Element item = (Element) tags.item(i);
89 String key = item.getAttribute("k");
90 if(m_tags.containsKey(key))
91 m_tags.put(key, m_tags.get(key)+","+item.getAttribute("v"));
92 else
93 m_tags.put(key, item.getAttribute("v"));
94 }
7995 }
8096
8197 /**
100100 @Override
101101 public boolean equals(java.lang.Object a_other)
102102 {
103 if(a_other instanceof API06Item)
103 if(!(a_other instanceof Item))
104 return false;
105 if(!((Item)a_other).getID().equals(getID()))
106 return false;
107 if(a_other instanceof VersionedItem)
104108 {
105 API06Item other = (API06Item) a_other;
106 return (getDOM().getTagName().equals(other.getDOM().getTagName()) && !getDOM().getAttribute("id").equals("") && getDOM().getAttribute("id").equals(other.getDOM().getAttribute("id")) && getDOM().getAttribute("version").equals(other.getDOM().getAttribute("version")));
109 if(!(this instanceof VersionedItem))
110 return false;
111 if(!((VersionedItem)a_other).getVersion().equals(((VersionedItem)this).getVersion()))
112 return false;
107113 }
108 else
109 return false;
114
115 if(a_other instanceof Node && this instanceof Node)
116 return true;
117 if(a_other instanceof Way && this instanceof Way)
118 return true;
119 if(a_other instanceof Relation && this instanceof Relation)
120 return true;
121 if(a_other instanceof Changeset && this instanceof Changeset)
122 return true;
123
124 return false;
110125 }
111126
112127 @Override
139139 @Override
140140 public ID getID()
141141 {
142 return new ID(getDOM().getAttribute("id"));
142 return m_id;
143143 }
144144
145145 @Override
152152 @Override
153153 public Map<String,String> getTags()
154154 {
155 if(m_tags == null)
156 {
157 m_tags = new Hashtable<String,String>();
158 NodeList tags = getDOM().getElementsByTagName("tag");
159 for(int i=0; i<tags.getLength(); i++)
160 {
161 if(tags.item(i).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE)
162 continue;
163 Element item = (Element) tags.item(i);
164 String key = item.getAttribute("k");
165 if(m_tags.containsKey(key))
166 m_tags.put(key, m_tags.get(key)+","+item.getAttribute("v"));
167 else
168 m_tags.put(key, item.getAttribute("v"));
169 }
170 }
171 return m_tags;
155 return Collections.unmodifiableMap(m_tags);
172156 }
173157}
  
2424import org.w3c.dom.Element;
2525
2626import eu.cdauth.osm.lib.APIError;
27import eu.cdauth.osm.lib.ID;
28import eu.cdauth.osm.lib.Item;
2729import eu.cdauth.osm.lib.LonLat;
2830import eu.cdauth.osm.lib.Node;
2931import eu.cdauth.osm.lib.VersionedItemCache;
3032import eu.cdauth.osm.lib.Way;
33import java.io.IOException;
34import java.io.ObjectInput;
35import java.io.ObjectOutput;
36import java.util.Arrays;
3137
3238/**
3339 * Represents a Node in OpenStreetMap.
4141
4242public class API06Node extends API06GeographicalItem implements Node
4343{
44 private LonLat m_lonlat = null;
45 private ID[] m_containingWays = null;
46
47 @Override
48 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
49 {
50 super.readExternal(in);
51 m_lonlat = (LonLat)in.readObject();
52 m_containingWays = (ID[])in.readObject();
53 }
54
55 @Override
56 public void writeExternal(ObjectOutput out) throws IOException
57 {
58 super.writeExternal(out);
59 out.writeObject(m_lonlat);
60 out.writeObject(m_containingWays);
61 }
62
4463 /**
4564 * Only for serialization.
4665 */
7171 protected API06Node(Element a_dom, API06API a_api)
7272 {
7373 super(a_dom, a_api);
74
75 m_lonlat = new LonLat(Double.parseDouble(a_dom.getAttribute("lon")), Double.parseDouble(a_dom.getAttribute("lat")));
7476 }
7577
7678 @Override
7779 public LonLat getLonLat()
7880 {
79 return new LonLat(Float.parseFloat(getDOM().getAttribute("lon")), Float.parseFloat(getDOM().getAttribute("lat")));
81 return m_lonlat;
8082 }
8183
8284 @Override
83 public Way[] getContainingWays() throws APIError
85 public ID[] getContainingWays() throws APIError
8486 {
85 Way[] ret = (Way[])getAPI().get("/node/"+getID()+"/ways");
86 VersionedItemCache<Way> cache = getAPI().getWayFactory().getCache();
87 for(Way it : ret)
87 if(m_containingWays == null)
8888 {
89 ((API06Way)it).markAsCurrent();
90 cache.cacheObject(it);
89 Item[] ways = getAPI().get("/node/"+getID()+"/ways");
90 VersionedItemCache<Way> cache = getAPI().getWayFactory().getCache();
91 synchronized(this)
92 {
93 m_containingWays = new ID[ways.length];
94 for(int i=0; i<ways.length; i++)
95 {
96 ((API06GeographicalItem)ways[i]).markAsCurrent();
97 cache.cacheObject((Way)ways[i]);
98 m_containingWays[i] = ways[i].getID();
99 }
100 }
91101 }
92102
93 // FIXME: Cache this result somehow?
94 return ret;
103 return Arrays.copyOf(m_containingWays, m_containingWays.length);
95104 }
96105}
  
3131import org.w3c.dom.NodeList;
3232
3333import eu.cdauth.osm.lib.GeographicalItem;
34import java.io.IOException;
35import java.io.ObjectInput;
36import java.io.ObjectOutput;
37import java.util.Arrays;
3438
3539public class API06Relation extends API06GeographicalItem implements Relation
3640{
41 private API06RelationMember[] m_members = null;
42
43 @Override
44 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
45 {
46 super.readExternal(in);
47 m_members = (API06RelationMember[])in.readObject();
48 }
49
50 @Override
51 public void writeExternal(ObjectOutput out) throws IOException
52 {
53 super.writeExternal(out);
54 out.writeObject(m_members);
55 }
56
3757 /**
3858 * Only for serialization.
3959 */
6565 protected API06Relation(Element a_dom, API06API a_api)
6666 {
6767 super(a_dom, a_api);
68
69 NodeList members = a_dom.getElementsByTagName("member");
70 m_members = new API06RelationMember[members.getLength()];
71 for(int i=0; i<members.getLength(); i++)
72 m_members[i] = new API06RelationMember((Element) members.item(i), getAPI(), getID());
6873 }
6974
7075 @Override
7176 public API06RelationMember[] getMembers()
7277 {
73 NodeList members = getDOM().getElementsByTagName("member");
74 API06RelationMember[] ret = new API06RelationMember[members.getLength()];
75 for(int i=0; i<members.getLength(); i++)
76 ret[i] = new API06RelationMember((Element) members.item(i), getAPI(), this);
77 return ret;
78 return Arrays.copyOf(m_members, m_members.length);
7879 }
7980
8081 /**
  
5858 if(type.equals(Node.class))
5959 isCached = (nodeCache.getObject(id) != null);
6060 else if(type.equals(Way.class))
61 isCached = (wayCache.getObject(id) != null);
61 isCached = (wayCache.getObject(id) != null); // FIXME: Download also necessary if some of the way”s member nodes are missing
6262 else if(type.equals(Relation.class))
6363 isCached = (relationCache.getObject(id) != null);
6464 if(!isCached)
  
2929import eu.cdauth.osm.lib.Relation;
3030import eu.cdauth.osm.lib.RelationMember;
3131import eu.cdauth.osm.lib.Way;
32import java.io.IOException;
33import java.io.ObjectInput;
34import java.io.ObjectOutput;
3235
3336public class API06RelationMember extends API06XMLItem implements RelationMember
3437{
35 private Relation m_relation; // Not final because of serialization
38 private String m_type = null;
39 private ID m_referenceID = null;
40 private ID m_relationID = null;
41 private String m_role = null;
3642
43 @Override
44 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
45 {
46 super.readExternal(in);
47 m_type = (String)in.readObject();
48 m_referenceID = (ID)in.readObject();
49 m_relationID = (ID)in.readObject();
50 m_role = (String)in.readObject();
51 }
52
53 @Override
54 public void writeExternal(ObjectOutput out) throws IOException
55 {
56 super.writeExternal(out);
57 out.writeObject(m_type);
58 out.writeObject(m_referenceID);
59 out.writeObject(m_relationID);
60 out.writeObject(m_role);
61 }
62
3763 /**
3864 * Only used for serialization.
3965 */
6868 {
6969 }
7070
71 protected API06RelationMember(Element a_dom, API06API a_api, Relation a_relation)
71 protected API06RelationMember(Element a_dom, API06API a_api, ID a_relation)
7272 {
7373 super(a_dom, a_api);
74 m_relation = a_relation;
74
75 m_relationID = a_relation;
76 m_type = a_dom.getAttribute("type");
77 m_referenceID = new ID(a_dom.getAttribute("ref"));
78 m_role = a_dom.getAttribute("role");
7579 }
7680
7781 @Override
78 public Relation getRelation()
82 public ID getRelation()
7983 {
80 return m_relation;
84 return m_relationID;
8185 }
8286
8387 @Override
8488 public Class<? extends GeographicalItem> getType()
8589 {
86 String type = getDOM().getAttribute("type");
87 if(type.equals("node"))
90 if(m_type.equals("node"))
8891 return Node.class;
89 else if(type.equals("way"))
92 else if(m_type.equals("way"))
9093 return Way.class;
91 else if(type.equals("relation"))
94 else if(m_type.equals("relation"))
9295 return Relation.class;
9396 else
94 throw new RuntimeException("Unknown relation member type "+type+".");
97 throw new RuntimeException("Unknown relation member type "+m_type+".");
9598 }
9699
97100 @Override
98101 public ID getReferenceID()
99102 {
100 return new ID(getDOM().getAttribute("ref"));
103 return m_referenceID;
101104 }
102105
103106 @Override
104107 public String getRole()
105108 {
106 return getDOM().getAttribute("role");
109 return m_role;
107110 }
108111}
  
3131import eu.cdauth.osm.lib.LonLat;
3232import eu.cdauth.osm.lib.Node;
3333import eu.cdauth.osm.lib.Way;
34import java.io.IOException;
35import java.io.ObjectInput;
36import java.io.ObjectOutput;
37import java.util.Arrays;
3438
3539public class API06Way extends API06GeographicalItem implements Way
3640{
41 private ID[] m_members = null;
42
43 @Override
44 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
45 {
46 super.readExternal(in);
47 m_members = (ID[])in.readObject();
48 }
49
50 @Override
51 public void writeExternal(ObjectOutput out) throws IOException
52 {
53 super.writeExternal(out);
54 out.writeObject(m_members);
55 }
56
3757 /**
3858 * Only for serialization.
3959 */
6565 protected API06Way(Element a_dom, API06API a_api)
6666 {
6767 super(a_dom, a_api);
68
69 NodeList members = a_dom.getElementsByTagName("nd");
70 m_members = new ID[members.getLength()];
71 for(int i=0; i<members.getLength(); i++)
72 m_members[i] = new ID(((Element)members.item(i)).getAttribute("ref"));
6873 }
6974
7075 /**
7979 @Override
8080 public ID[] getMembers()
8181 {
82 NodeList members = getDOM().getElementsByTagName("nd");
83 ID[] ret = new ID[members.getLength()];
84 for(int i=0; i<members.getLength(); i++)
85 ret[i] = new ID(((Element)members.item(i)).getAttribute("ref"));
86 return ret;
82 return Arrays.copyOf(m_members, m_members.length);
8783 }
88
84
85 @Override
8986 public Node[] getMemberNodes(Date a_date) throws APIError
9087 {
9188 if(a_date != null)
92 getAPI().getWayFactory().downloadFull(new ID(getDOM().getAttribute("id")));
89 getAPI().getWayFactory().downloadFull(getID());
9390 ID[] members = getMembers();
9491 Node[] ret = new Node[members.length];
9592 for(int i=0; i<members.length; i++)
  
1/*
2 Copyright © 2010 Candid Dauth
3
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the “Software”),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the Software
9 is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*/
21
22package eu.cdauth.osm.lib.api06;
23
24import org.w3c.dom.Element;
25import org.w3c.dom.bootstrap.DOMImplementationRegistry;
26import org.w3c.dom.ls.DOMImplementationLS;
27import org.w3c.dom.ls.LSInput;
28import org.w3c.dom.ls.LSParser;
29import org.w3c.dom.ls.LSSerializer;
30
31import java.io.*;
32
33/**
34 * Abstract class for all objects whose information is saved in an XML DOM element.
35 */
36abstract public class API06XMLItem implements Externalizable
37{
38 private transient API06API m_api;
39
40 @Override
41 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
42 {
43 }
44
45 @Override
46 public void writeExternal(ObjectOutput out) throws IOException
47 {
48 }
49
50 /**
51 * Only for serialization.
52 */
53 @Deprecated
54 public API06XMLItem()
55 {
56 }
57
58 /**
59 * @param a_dom The DOM element.
60 * @param a_api The API that creates this object.
61 */
62
63 protected API06XMLItem(Element a_dom, API06API a_api)
64 {
65 m_api = a_api;
66 }
67
68 protected void setAPI(API06API a_api)
69 {
70 m_api = a_api;
71 }
72
73 protected API06API getAPI()
74 {
75 return m_api;
76 }
77}
  
1/*
2 Copyright © 2010 Candid Dauth
3
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the “Software”),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the Software
9 is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*/
21
22package eu.cdauth.osm.lib.api06;
23
24import java.io.BufferedOutputStream;
25import java.io.ByteArrayInputStream;
26import java.io.ByteArrayOutputStream;
27import java.io.ObjectInputStream;
28import java.io.ObjectOutputStream;
29import java.io.Serializable;
30import org.junit.Test;
31import static org.junit.Assert.*;
32
33public class SerializationTest
34{
35 public <T extends Serializable> T reconstruct(T a_object) throws Exception
36 {
37 ByteArrayOutputStream ser = new ByteArrayOutputStream();
38 BufferedOutputStream ser2 = new BufferedOutputStream(ser);
39 ObjectOutputStream ser3 = new ObjectOutputStream(ser2);
40 ser3.writeObject(a_object);
41 ser3.close();
42
43 ByteArrayInputStream ser4 = new ByteArrayInputStream(ser.toByteArray());
44 ObjectInputStream ser5 = new ObjectInputStream(ser4);
45 T ret = (T) ser5.readObject();
46 ser5.close();
47
48 return ret;
49 }
50
51 @Test
52 public void node() throws Exception
53 {
54 API06Node node = XMLReadTest.makeNode();
55 API06Node clone = reconstruct(node);
56
57 assertEquals(node, clone);
58 assertEquals(node.getID(), clone.getID());
59 assertEquals(node.getLonLat(), clone.getLonLat());
60 assertEquals(node.getVersion(), clone.getVersion());
61 assertEquals(node.getChangeset(), clone.getChangeset());
62 assertEquals(node.getTimestamp(), clone.getTimestamp());
63 assertEquals(node.getTags(), clone.getTags());
64 }
65}
  
1/*
2 Copyright © 2010 Candid Dauth
3
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the “Software”),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the Software
9 is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*/
21
22package eu.cdauth.osm.lib.api06;
23
24import eu.cdauth.osm.lib.Item;
25import java.io.ByteArrayInputStream;
26import java.io.IOException;
27import java.util.List;
28import javax.xml.parsers.DocumentBuilderFactory;
29import javax.xml.parsers.ParserConfigurationException;
30import org.junit.Test;
31import static org.junit.Assert.*;
32import org.w3c.dom.Document;
33import org.w3c.dom.Element;
34import org.w3c.dom.NodeList;
35import org.xml.sax.SAXException;
36
37public class XMLReadTest
38{
39 public static final API06API sm_api = new API06API();
40
41 public static API06Item makeItem(String a_xml) throws Exception
42 {
43 Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(a_xml.getBytes("UTF-8")));
44 Element root = null;
45 NodeList nodes = dom.getChildNodes();
46 for(int i=0; i<nodes.getLength(); i++)
47 {
48 if(nodes.item(i).getNodeType() != org.w3c.dom.Node.ELEMENT_NODE)
49 continue;
50 root = (Element) nodes.item(i);
51 break;
52 }
53
54 if(root == null)
55 throw new IOException("No root element.");
56
57 List<Item> items = sm_api.makeObjects(root);
58 if(items.size() < 1)
59 throw new IOException("No items.");
60
61 return (API06Item)items.get(0);
62 }
63
64 public static API06Node makeNode() throws Exception
65 {
66 return (API06Node)makeItem("<osm version=\"0.6\" generator=\"OpenStreetMap server\">" +
67 "<node id=\"123456\" lat=\"51.2153688\" lon=\"4.089274\" version=\"8\" changeset=\"359445\" user=\"Benjamiini\" uid=\"65172\" visible=\"true\" timestamp=\"2008-12-13T15:05:11Z\">" +
68 "<tag k=\"tourism\" v=\"camp_site\"/>" +
69 "<tag k=\"name\" v=\"Bariş Camping\"/>" +
70 "</node>" +
71 "</osm>");
72 }
73
74 @Test
75 public void node() throws Exception
76 {
77 API06Node node = makeNode();
78
79 assertEquals(node.getID().asLong().longValue(), 123456L);
80 assertEquals(node.getLonLat().getLon(), 4.089274D, 0.00000005D);
81 assertEquals(node.getLonLat().getLat(), 51.2153688D, 0.00000005D);
82 assertEquals(node.getVersion().asLong().longValue(), 8L);
83 assertEquals(node.getChangeset().asLong().longValue(), 359445L);
84 assertEquals(node.getTimestamp().getTime(), 1229180711000L);
85 assertEquals(node.getTags().size(), 2);
86 assertEquals(node.getTag("tourism"), "camp_site");
87 assertEquals(node.getTag("name"), "Bariş Camping");
88 }
89}
  
1414public interface GeographicalItem extends Item
1515{
1616 /**
17 * Returns all relations that the <strong>current</strong> version of this object is currently contained in.
17 * Returns the IDs all relations that the <strong>current</strong> version of this object is currently contained in.
1818 * Relations can only contain geographical objects.
19 * @return The relations that contain this object.
19 * @return The IDs of the relations that contain this object.
2020 * @throws APIError There was an error fetching the relations.
2121 */
22 public Relation[] getContainingRelations() throws APIError;
22 public ID[] getContainingRelations() throws APIError;
2323}
  
3838 /**
3939 * How many entries may be in the database cache?
4040 */
41 public static final int MAX_DATABASE_VALUES = 5000;
41 public static final int MAX_DATABASE_VALUES = 50000;
4242 /**
4343 * How old may the entries in the database cache be at most? (seconds)
4444 */
159159 {
160160 synchronized(m_cacheTimes)
161161 {
162 m_cache.put(id, a_object);
162 T old = m_cache.get(id);
163 if(old == null || !old.equals(a_object)) // Prevent additionally downloaded data (for example the content of a changeset) from being lost.
164 m_cache.put(id, a_object);
163165 m_cacheTimes.put(id, System.currentTimeMillis());
164166 }
165167 }
197197 /**
198198 * Clean up entries from the memory cache that exceed {@link #MAX_CACHED_VALUES} or {@link #MAX_AGE}. If a database
199199 * cache is used, the entries are moved there.
200 * @param a_completely If set to true, the memory cache will be cleared completely, not just up to {@link #MAX_CACHED_VALUES} (useful at shutdown)
200201 */
201 protected void cleanUpMemory()
202 protected void cleanUpMemory(boolean a_completely)
202203 {
203204 String persistenceID = getPersistenceID();
204205 Connection conn = null;
229229 break;
230230 ID oldest = m_cacheTimes.firstKey();
231231 long oldestTime = m_cacheTimes.get(oldest);
232 if(System.currentTimeMillis()-oldestTime <= MAX_AGE*1000 && m_cacheTimes.size() <= MAX_CACHED_VALUES)
232 if(!a_completely && System.currentTimeMillis()-oldestTime <= MAX_AGE*1000 && m_cacheTimes.size() <= MAX_CACHED_VALUES)
233233 break;
234234 m_cacheTimes.remove(oldest);
235235 item = m_cache.remove(oldest);
395395
396396 /**
397397 * Runs {@link #cleanUpMemory()} and {@link #cleanUpDatabase()} on all instances of this class.
398 * @param a_completely If set to true, the memory cache is cleared completely instead of just to {@link #MAX_CACHED_VALUES}.
398399 */
399 public static void cleanUpAll()
400 public static void cleanUpAll(boolean a_completely)
400401 {
401402 ItemCache<? extends Item>[] instances;
402403 synchronized(sm_instances)
416416 number++;
417417 try
418418 {
419 instance.cleanUpMemory();
419 instance.cleanUpMemory(a_completely);
420420 instance.cleanUpDatabase();
421421 }
422422 catch(Exception e)
  
5858
5959 /**
6060 * Two LonLat objects are equal if their coordinates are the same.
61 * The OpenStreetMap database saves 7 decimals for each coordinate. If lower decimals differ, this is a result of computation errors
62 * and is ignored.
6163 *
6264 * <p>{@inheritDoc}
6365 */
7171 if(a_other instanceof LonLat)
7272 {
7373 LonLat other = (LonLat) a_other;
74 return (getLon() == other.getLon() && getLat() == other.getLat());
74 return (Math.abs(getLon()-other.getLon()) < 0.00000005D && Math.abs(getLat()-other.getLat()) < 0.00000005D);
7575 }
7676 return false;
7777 }
  
1919 public LonLat getLonLat();
2020
2121 /**
22 * Returns all ways that currently contain the <strong>current</strong> version of this node.
23 * @return An array of ways that currently contain this node.
22 * Returns the ID of all ways that currently contain the <strong>current</strong> version of this node.
23 * @return An array of the IDs of all ways that currently contain this node.
2424 * @throws APIError The ways could not be fetched.
2525 */
26 public Way[] getContainingWays() throws APIError;
26 public ID[] getContainingWays() throws APIError;
2727}
  
2121public interface RelationMember extends Serializable
2222{
2323 /**
24 * Returns the corresponding {@link Relation} that this member belongs to.
25 * @return The relation that contains this member.
24 * Returns the corresponding {@link Relation} ID that this member belongs to.
25 * @return The ID of the relation that contains this member.
2626 */
27 public Relation getRelation();
27 public ID getRelation();
2828
2929 /**
3030 * Returns the type of the {@link GeographicalItem} that this member refers to.
  
205205 }
206206
207207 @Override
208 protected void cleanUpMemory()
208 protected void cleanUpMemory(boolean a_completely)
209209 {
210 super.cleanUpMemory();
210 super.cleanUpMemory(a_completely);
211211
212212 String persistenceID = getPersistenceID();
213213 Connection conn = null;
237237 break;
238238 ID oldest = m_historyTimes.firstKey();
239239 long oldestTime = m_historyTimes.get(oldest);
240 if(System.currentTimeMillis()-oldestTime <= MAX_AGE*1000 && m_historyTimes.size() <= MAX_CACHED_VALUES)
240 if(!a_completely && System.currentTimeMillis()-oldestTime <= MAX_AGE*1000 && m_historyTimes.size() <= MAX_CACHED_VALUES)
241241 break;
242242 id = oldest;
243243 m_historyTimes.remove(oldest);
pom.xml
(1 / 1)
  
120120 <plugin>
121121 <groupId>org.xnap.commons</groupId>
122122 <artifactId>maven-gettext-plugin</artifactId>
123 <version>1.2.0</version>
123 <version>1.2.1</version>
124124 <executions>
125125 <execution>
126126 <phase>compile</phase>
  
6868 private final HttpServletResponse m_resp;
6969
7070 private static API06API sm_api = null;
71 private static Timer sm_apiCleanUp = null;
71 private static Thread sm_apiCleanUp = null;
72
73 private static int sm_servletsRunning = 0;
7274
75 public synchronized static void servletStart()
76 {
77 if(sm_servletsRunning++ == 0)
78 {
79 Logger.getLogger(GUI.class.getName()).info("Starting cache cleanup thread.");
80 sm_apiCleanUp = new Thread("osmrmhv cache cleanup") {
81 @Override public void run() {
82 while(true)
83 {
84 try {
85 Thread.sleep(60000);
86 } catch(InterruptedException e) {
87 break;
88 }
89 try {
90 ItemCache.cleanUpAll(false);
91 } catch(Exception e) {
92 Logger.getLogger(GUI.class.getName()).log(Level.WARNING, "Unexpected exception.", e);
93 }
94 }
95 }
96 };
97 sm_apiCleanUp.start();
98 }
99 }
100
101 public synchronized static void servletStop()
102 {
103 if(--sm_servletsRunning == 0)
104 {
105 Logger.getLogger(GUI.class.getName()).info("Stopping cache cleanup thread, completely clearing memory.");
106 sm_apiCleanUp.interrupt();
107 sm_apiCleanUp = null;
108 ItemCache.cleanUpAll(true);
109 }
110 }
111
73112 /**
74113 * Returns an {@link eu.cdauth.osm.lib.API} object to use.
75114 * @return The API object to use.
132132 Logger.getLogger(GUI.class.getName()).info("Using API with database cache.");
133133 sm_api = new eu.cdauth.osm.lib.api06.API06API(ds);
134134 }
135
136 new Thread("osmrmhv cache cleanup") {
137 @Override public void run() {
138 while(true)
139 {
140 try {
141 Thread.sleep(60000);
142 } catch(InterruptedException e) {
143 break;
144 }
145 try {
146 ItemCache.cleanUpAll();
147 } catch(Exception e) {
148 Logger.getLogger(GUI.class.getName()).log(Level.WARNING, "Unexpected exception.", e);
149 }
150 }
151 }
152 }.start();
153135 }
154136 return sm_api;
155137 }
  
237237 }*/
238238
239239 // Second guess: Current parent nodes of the node
240 for(Way obj : node.getContainingWays())
240 for(Way obj : a_api.getWayFactory().fetch(node.getContainingWays()).values())
241241 {
242242 if(waysChanged.containsKey(obj.getID()))
243243 continue;
  
5252 return a_other.changes.compareTo(changes);
5353 }
5454 }
55
56 public void jspInit()
57 {
58 GUI.servletStart();
59 }
60
61 public void jspDestroy()
62 {
63 GUI.servletStop();
64 }
5565%>
5666<%
5767 if(request.getParameter("id") == null)
  
2424<%@page contentType="text/html; charset=UTF-8" buffer="none" session="false"%>
2525<%!
2626 protected static final API api = GUI.getAPI();
27
28 public void jspInit()
29 {
30 GUI.servletStart();
31 }
32
33 public void jspDestroy()
34 {
35 GUI.servletStop();
36 }
2737%>
2838<%
2939 if(request.getParameter("id") == null)
  
2323<%@page contentType="text/html; charset=UTF-8" buffer="none" session="false"%>
2424<%!
2525 protected static final API api = GUI.getAPI();
26
27 public void jspInit()
28 {
29 GUI.servletStart();
30 }
31
32 public void jspDestroy()
33 {
34 GUI.servletStop();
35 }
2636%>
2737<%
2838 GUI gui = new GUI(request, response);
  
2323<%@page contentType="text/xml; charset=UTF-8" buffer="none" session="false"%>
2424<%!
2525 private static API api = GUI.getAPI();
26
27 public void jspInit()
28 {
29 GUI.servletStart();
30 }
31
32 public void jspDestroy()
33 {
34 GUI.servletStop();
35 }
2636%>
2737<%
2838 response.setHeader("Content-disposition", "attachment; filename=route.gpx");
  
2323<%@page contentType="text/html; charset=UTF-8" buffer="none" session="false"%>
2424<%!
2525 protected static final API api = GUI.getAPI();
26
27 public void jspInit()
28 {
29 GUI.servletStart();
30 }
31
32 public void jspDestroy()
33 {
34 GUI.servletStop();
35 }
2636%>
2737<%
2838 GUI gui = new GUI(request, response);
  
2424<%@page contentType="text/html; charset=UTF-8" buffer="none" session="false"%>
2525<%!
2626 private static final API api = GUI.getAPI();
27
28 public void jspInit()
29 {
30 GUI.servletStart();
31 }
32
33 public void jspDestroy()
34 {
35 GUI.servletStop();
36 }
2737%>
2838<%
2939 if(request.getParameter("id") == null)
257257 <dt><%=htmlspecialchars(gui._("Parent relations"))%></dt>
258258 <dd><ul>
259259<%
260 Relation[] parentRelations = relation.getContainingRelations();
261 for(Relation parentRelation : parentRelations)
260 Map<ID,Relation> parentRelations = api.getRelationFactory().fetch(relation.getContainingRelations());
261 for(Map.Entry<ID,Relation> parentRelation : parentRelations.entrySet())
262262 {
263263%>
264 <li><a href="?id=<%=htmlspecialchars(urlencode(parentRelation.getID().toString()))%>"><%=htmlspecialchars(parentRelation.getID().toString())%> (<%=htmlspecialchars(parentRelation.getTag("name"))%>)</a></li>
264 <li><a href="?id=<%=htmlspecialchars(urlencode(parentRelation.getKey().toString()))%>"><%=htmlspecialchars(parentRelation.getKey().toString())%> (<%=htmlspecialchars(parentRelation.getValue().getTag("name"))%>)</a></li>
265265<%
266266 }
267267%>