OSDN Git Service

Make copy-constructor make deep copy.
[android-x86/frameworks-base.git] / core / java / android / net / LinkProperties.java
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package android.net;
18
19 import android.net.ProxyProperties;
20 import android.os.Parcelable;
21 import android.os.Parcel;
22 import android.text.TextUtils;
23
24 import java.net.InetAddress;
25 import java.net.UnknownHostException;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Collections;
29
30 /**
31  * Describes the properties of a network link.
32  *
33  * A link represents a connection to a network.
34  * It may have multiple addresses and multiple gateways,
35  * multiple dns servers but only one http proxy.
36  *
37  * Because it's a single network, the dns's
38  * are interchangeable and don't need associating with
39  * particular addresses.  The gateways similarly don't
40  * need associating with particular addresses.
41  *
42  * A dual stack interface works fine in this model:
43  * each address has it's own prefix length to describe
44  * the local network.  The dns servers all return
45  * both v4 addresses and v6 addresses regardless of the
46  * address family of the server itself (rfc4213) and we
47  * don't care which is used.  The gateways will be
48  * selected based on the destination address and the
49  * source address has no relavence.
50  * @hide
51  */
52 public class LinkProperties implements Parcelable {
53
54     String mIfaceName;
55     private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
56     private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
57     private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
58     private ProxyProperties mHttpProxy;
59
60     public static class CompareResult<T> {
61         public Collection<T> removed = new ArrayList<T>();
62         public Collection<T> added = new ArrayList<T>();
63
64         @Override
65         public String toString() {
66             String retVal = "removed=[";
67             for (T addr : removed) retVal += addr.toString() + ",";
68             retVal += "] added=[";
69             for (T addr : added) retVal += addr.toString() + ",";
70             retVal += "]";
71             return retVal;
72         }
73     }
74
75     public LinkProperties() {
76         clear();
77     }
78
79     // copy constructor instead of clone
80     public LinkProperties(LinkProperties source) {
81         if (source != null) {
82             mIfaceName = source.getInterfaceName();
83             for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
84             for (InetAddress i : source.getDnses()) mDnses.add(i);
85             for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
86             mHttpProxy = (source.getHttpProxy() == null)  ?
87                 null : new ProxyProperties(source.getHttpProxy());
88         }
89     }
90
91     public void setInterfaceName(String iface) {
92         mIfaceName = iface;
93     }
94
95     public String getInterfaceName() {
96         return mIfaceName;
97     }
98
99     public Collection<InetAddress> getAddresses() {
100         Collection<InetAddress> addresses = new ArrayList<InetAddress>();
101         for (LinkAddress linkAddress : mLinkAddresses) {
102             addresses.add(linkAddress.getAddress());
103         }
104         return Collections.unmodifiableCollection(addresses);
105     }
106
107     public void addLinkAddress(LinkAddress address) {
108         if (address != null) mLinkAddresses.add(address);
109     }
110
111     public Collection<LinkAddress> getLinkAddresses() {
112         return Collections.unmodifiableCollection(mLinkAddresses);
113     }
114
115     public void addDns(InetAddress dns) {
116         if (dns != null) mDnses.add(dns);
117     }
118
119     public Collection<InetAddress> getDnses() {
120         return Collections.unmodifiableCollection(mDnses);
121     }
122
123     public void addRoute(RouteInfo route) {
124         if (route != null) mRoutes.add(route);
125     }
126     public Collection<RouteInfo> getRoutes() {
127         return Collections.unmodifiableCollection(mRoutes);
128     }
129
130     public void setHttpProxy(ProxyProperties proxy) {
131         mHttpProxy = proxy;
132     }
133     public ProxyProperties getHttpProxy() {
134         return mHttpProxy;
135     }
136
137     public void clear() {
138         mIfaceName = null;
139         mLinkAddresses.clear();
140         mDnses.clear();
141         mRoutes.clear();
142         mHttpProxy = null;
143     }
144
145     /**
146      * Implement the Parcelable interface
147      * @hide
148      */
149     public int describeContents() {
150         return 0;
151     }
152
153     @Override
154     public String toString() {
155         String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
156
157         String linkAddresses = "LinkAddresses: [";
158         for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
159         linkAddresses += "] ";
160
161         String dns = "DnsAddresses: [";
162         for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
163         dns += "] ";
164
165         String routes = "Routes: [";
166         for (RouteInfo route : mRoutes) routes += route.toString() + ",";
167         routes += "] ";
168         String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
169
170         return ifaceName + linkAddresses + routes + dns + proxy;
171     }
172
173     /**
174      * Compares this {@code LinkProperties} interface name against the target
175      *
176      * @param target LinkProperties to compare.
177      * @return {@code true} if both are identical, {@code false} otherwise.
178      */
179     public boolean isIdenticalInterfaceName(LinkProperties target) {
180         return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
181     }
182
183     /**
184      * Compares this {@code LinkProperties} interface name against the target
185      *
186      * @param target LinkProperties to compare.
187      * @return {@code true} if both are identical, {@code false} otherwise.
188      */
189     public boolean isIdenticalAddresses(LinkProperties target) {
190         Collection<InetAddress> targetAddresses = target.getAddresses();
191         Collection<InetAddress> sourceAddresses = getAddresses();
192         return (sourceAddresses.size() == targetAddresses.size()) ?
193                     sourceAddresses.containsAll(targetAddresses) : false;
194     }
195
196     /**
197      * Compares this {@code LinkProperties} DNS addresses against the target
198      *
199      * @param target LinkProperties to compare.
200      * @return {@code true} if both are identical, {@code false} otherwise.
201      */
202     public boolean isIdenticalDnses(LinkProperties target) {
203         Collection<InetAddress> targetDnses = target.getDnses();
204         return (mDnses.size() == targetDnses.size()) ?
205                     mDnses.containsAll(targetDnses) : false;
206     }
207
208     /**
209      * Compares this {@code LinkProperties} Routes against the target
210      *
211      * @param target LinkProperties to compare.
212      * @return {@code true} if both are identical, {@code false} otherwise.
213      */
214     public boolean isIdenticalRoutes(LinkProperties target) {
215         Collection<RouteInfo> targetRoutes = target.getRoutes();
216         return (mRoutes.size() == targetRoutes.size()) ?
217                     mRoutes.containsAll(targetRoutes) : false;
218     }
219
220     /**
221      * Compares this {@code LinkProperties} HttpProxy against the target
222      *
223      * @param target LinkProperties to compare.
224      * @return {@code true} if both are identical, {@code false} otherwise.
225      */
226     public boolean isIdenticalHttpProxy(LinkProperties target) {
227         return getHttpProxy() == null ? target.getHttpProxy() == null :
228                     getHttpProxy().equals(target.getHttpProxy());
229     }
230
231     @Override
232     /**
233      * Compares this {@code LinkProperties} instance against the target
234      * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
235      * all their fields are equal in values.
236      *
237      * For collection fields, such as mDnses, containsAll() is used to check
238      * if two collections contains the same elements, independent of order.
239      * There are two thoughts regarding containsAll()
240      * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
241      * 2. Worst case performance is O(n^2).
242      *
243      * @param obj the object to be tested for equality.
244      * @return {@code true} if both objects are equal, {@code false} otherwise.
245      */
246     public boolean equals(Object obj) {
247         if (this == obj) return true;
248
249         if (!(obj instanceof LinkProperties)) return false;
250
251         LinkProperties target = (LinkProperties) obj;
252
253         return isIdenticalInterfaceName(target) &&
254                 isIdenticalAddresses(target) &&
255                 isIdenticalDnses(target) &&
256                 isIdenticalRoutes(target) &&
257                 isIdenticalHttpProxy(target);
258     }
259
260     /**
261      * Return two lists, a list of addresses that would be removed from
262      * mLinkAddresses and a list of addresses that would be added to
263      * mLinkAddress which would then result in target and mLinkAddresses
264      * being the same list.
265      *
266      * @param target is a LinkProperties with the new list of addresses
267      * @return the removed and added lists.
268      */
269     public CompareResult<LinkAddress> compareAddresses(LinkProperties target) {
270         /*
271          * Duplicate the LinkAddresses into removed, we will be removing
272          * address which are common between mLinkAddresses and target
273          * leaving the addresses that are different. And address which
274          * are in target but not in mLinkAddresses are placed in the
275          * addedAddresses.
276          */
277         CompareResult<LinkAddress> result = new CompareResult<LinkAddress>();
278         result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
279         result.added.clear();
280         if (target != null) {
281             for (LinkAddress newAddress : target.getLinkAddresses()) {
282                 if (! result.removed.remove(newAddress)) {
283                     result.added.add(newAddress);
284                 }
285             }
286         }
287         return result;
288     }
289
290     /**
291      * Return two lists, a list of dns addresses that would be removed from
292      * mDnses and a list of addresses that would be added to
293      * mDnses which would then result in target and mDnses
294      * being the same list.
295      *
296      * @param target is a LinkProperties with the new list of dns addresses
297      * @return the removed and added lists.
298      */
299     public CompareResult<InetAddress> compareDnses(LinkProperties target) {
300         /*
301          * Duplicate the InetAddresses into removed, we will be removing
302          * dns address which are common between mDnses and target
303          * leaving the addresses that are different. And dns address which
304          * are in target but not in mDnses are placed in the
305          * addedAddresses.
306          */
307         CompareResult<InetAddress> result = new CompareResult<InetAddress>();
308
309         result.removed = new ArrayList<InetAddress>(mDnses);
310         result.added.clear();
311         if (target != null) {
312             for (InetAddress newAddress : target.getDnses()) {
313                 if (! result.removed.remove(newAddress)) {
314                     result.added.add(newAddress);
315                 }
316             }
317         }
318         return result;
319     }
320
321     /**
322      * Return two lists, a list of routes that would be removed from
323      * mRoutes and a list of routes that would be added to
324      * mRoutes which would then result in target and mRoutes
325      * being the same list.
326      *
327      * @param target is a LinkProperties with the new list of routes
328      * @return the removed and added lists.
329      */
330     public CompareResult<RouteInfo> compareRoutes(LinkProperties target) {
331         /*
332          * Duplicate the RouteInfos into removed, we will be removing
333          * routes which are common between mDnses and target
334          * leaving the routes that are different. And route address which
335          * are in target but not in mRoutes are placed in added.
336          */
337         CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
338
339         result.removed = new ArrayList<RouteInfo>(mRoutes);
340         result.added.clear();
341         if (target != null) {
342             for (RouteInfo r : target.getRoutes()) {
343                 if (! result.removed.remove(r)) {
344                     result.added.add(r);
345                 }
346             }
347         }
348         return result;
349     }
350
351
352     @Override
353     /**
354      * generate hashcode based on significant fields
355      * Equal objects must produce the same hash code, while unequal objects
356      * may have the same hash codes.
357      */
358     public int hashCode() {
359         return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
360                 + mLinkAddresses.size() * 31
361                 + mDnses.size() * 37
362                 + mRoutes.size() * 41
363                 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()));
364     }
365
366     /**
367      * Implement the Parcelable interface.
368      * @hide
369      */
370     public void writeToParcel(Parcel dest, int flags) {
371         dest.writeString(getInterfaceName());
372         dest.writeInt(mLinkAddresses.size());
373         for(LinkAddress linkAddress : mLinkAddresses) {
374             dest.writeParcelable(linkAddress, flags);
375         }
376
377         dest.writeInt(mDnses.size());
378         for(InetAddress d : mDnses) {
379             dest.writeByteArray(d.getAddress());
380         }
381
382         dest.writeInt(mRoutes.size());
383         for(RouteInfo route : mRoutes) {
384             dest.writeParcelable(route, flags);
385         }
386
387         if (mHttpProxy != null) {
388             dest.writeByte((byte)1);
389             dest.writeParcelable(mHttpProxy, flags);
390         } else {
391             dest.writeByte((byte)0);
392         }
393     }
394
395     /**
396      * Implement the Parcelable interface.
397      * @hide
398      */
399     public static final Creator<LinkProperties> CREATOR =
400         new Creator<LinkProperties>() {
401             public LinkProperties createFromParcel(Parcel in) {
402                 LinkProperties netProp = new LinkProperties();
403                 String iface = in.readString();
404                 if (iface != null) {
405                     try {
406                         netProp.setInterfaceName(iface);
407                     } catch (Exception e) {
408                         return null;
409                     }
410                 }
411                 int addressCount = in.readInt();
412                 for (int i=0; i<addressCount; i++) {
413                     netProp.addLinkAddress((LinkAddress)in.readParcelable(null));
414                 }
415                 addressCount = in.readInt();
416                 for (int i=0; i<addressCount; i++) {
417                     try {
418                         netProp.addDns(InetAddress.getByAddress(in.createByteArray()));
419                     } catch (UnknownHostException e) { }
420                 }
421                 addressCount = in.readInt();
422                 for (int i=0; i<addressCount; i++) {
423                     netProp.addRoute((RouteInfo)in.readParcelable(null));
424                 }
425                 if (in.readByte() == 1) {
426                     netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
427                 }
428                 return netProp;
429             }
430
431             public LinkProperties[] newArray(int size) {
432                 return new LinkProperties[size];
433             }
434         };
435 }