5151d300c8ba8d8428e5fd8976810079af9e5a91
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / sal / convertor / IpConversionUtil.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc., Brocade, Communications Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
10
11 import java.math.BigInteger;
12 import java.net.Inet4Address;
13 import java.net.InetAddress;
14 import java.net.UnknownHostException;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Iterator;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IetfInetUtil;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
25 import com.google.common.base.Preconditions;
26 import com.google.common.base.Splitter;
27 import com.google.common.base.Strings;
28 import com.google.common.collect.Iterators;
29 import com.google.common.net.InetAddresses;
30 import com.google.common.primitives.UnsignedBytes;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DottedQuad;
32
33
34 /**
35  * Created by Martin Bobak <mbobak@cisco.com> on 5.3.2015.
36  * v6 routines added by Anton Ivanov on 14.6.2015
37  * Arbitrary masks by sai.marapareddy@gmail.com
38  */
39 public final class IpConversionUtil {
40
41     private static final Logger LOG = LoggerFactory.getLogger(IpConversionUtil.class);
42     public static final String PREFIX_SEPARATOR = "/";
43     public static final Splitter PREFIX_SPLITTER = Splitter.on('/');
44     private static final int INADDR4SZ = 4;
45     private static final int INADDR6SZ = 16;
46     private static final int INT16SZ = 2;
47     private static final int IPV4_ADDRESS_LENGTH = 32;
48     private static final int IPV6_ADDRESS_LENGTH = 128;
49     private static final String DEFAULT_ARBITRARY_BIT_MASK = "255.255.255.255";
50
51     /*
52      * Prefix bytearray lookup table. We concatenate the prefixes
53      * to a single byte array and perform offset lookups to ensure
54      * the table is contiguous and save some space.
55      */
56     private static final byte[] PREFIX_BYTEARRAYS;
57     static {
58         final byte[] a = new byte[(INADDR6SZ * Byte.SIZE + 1) * INADDR6SZ];
59
60         int offset = 0;
61         for (int p = 0; p <= INADDR6SZ * Byte.SIZE; ++p) {
62             int prefix = p;
63             for (int i = 0; i < INADDR6SZ; ++i) {
64                 a[offset++] = (byte) nextNibble(prefix);
65                 prefix -= Byte.SIZE;
66             }
67         }
68
69         PREFIX_BYTEARRAYS = a;
70     }
71
72     private IpConversionUtil() {
73         throw new UnsupportedOperationException("This class should not be instantiated.");
74     }
75
76     public static Iterator<String> splitToParts(final Ipv4Prefix ipv4Prefix) {
77         return PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
78     }
79
80     public static Iterator<String> splitToParts(final Ipv4Address ipv4Address) {
81         /* Invalid (Ab)use of ip address as prefix!!! */
82         return Iterators.forArray(ipv4Address.getValue(), String.valueOf(IPV4_ADDRESS_LENGTH));
83     }
84
85     public static Iterator<String> splitToParts(final Ipv6Prefix ipv6Prefix) {
86         return PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
87     }
88
89     public static Iterator<String> splitToParts(final Ipv6Address ipv6Address) {
90         /* Invalid (Ab)use of ip address as prefix!!! */
91         return Iterators.forArray(ipv6Address.getValue(), String.valueOf(IPV6_ADDRESS_LENGTH));
92     }
93
94     /* This forest of functions has a purpose:
95      *
96      * 1. There are multiple coding styles around the plugin, this is necessary in order to have
97      *   one mechanism to convert them all, one mechanism to find them...
98      * 2. I hope that one day yangtools will actually deliver code fit for purpose in a packet
99      *   processing application (presently it is not. When this happens, these can be optimized
100      *   for "side-load" of pre-vetted data. Example. IP Address (v4 or v6) is prevetted left of the
101      *   prefix. It should be loadable into Prefix without _RERUNNING_ 100ms+ of regexps. When (and if)
102      *   that happens, it will be a simple fix here without chasing it across the whole plugin.
103     */
104
105     public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address){
106         return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address);
107     }
108
109     public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final String mask){
110         /*
111          * Ipv4Address has already validated the address part of the prefix,
112          * It is mandated to comply to the same regexp as the address
113          * There is absolutely no point rerunning additional checks vs this
114          * Note - there is no canonical form check here!!!
115          */
116         if (null != mask && !mask.isEmpty()) {
117             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
118         } else {
119             return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + IPV4_ADDRESS_LENGTH);
120         }
121     }
122
123     public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final int intmask){
124         return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, intmask);
125     }
126
127     public static Ipv4Prefix createPrefix(final Ipv4Address ipv4Address, final byte [] bytemask){
128         return IetfInetUtil.INSTANCE.ipv4PrefixFor(ipv4Address, countBits(bytemask));
129     }
130
131     public static DottedQuad createArbitraryBitMask(final byte [] bytemask)  {
132         DottedQuad dottedQuad = new DottedQuad(DEFAULT_ARBITRARY_BIT_MASK);
133         try {
134             dottedQuad = new DottedQuad(InetAddress.getByAddress(bytemask).getHostAddress());
135         } catch (UnknownHostException e) {
136             LOG.error("Failed to create the dottedQuad notation for the given mask ", e);
137         }
138         return dottedQuad;
139     }
140
141     public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address){
142         return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address);
143     }
144
145     public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final String mask){
146         /*
147          * Ipv6Address has already validated the address part of the prefix,
148          * It is mandated to comply to the same regexp as the address
149          * There is absolutely no point rerunning additional checks vs this
150          * Note - there is no canonical form check here!!!
151          */
152         if (Strings.isNullOrEmpty(mask)) {
153             return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + String.valueOf(IPV6_ADDRESS_LENGTH));
154         } else {
155             return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
156         }
157     }
158
159     public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final int intmask){
160         return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, intmask);
161     }
162
163     public static Ipv6Prefix createPrefix(final Ipv6Address ipv6Address, final byte [] bytemask){
164         return IetfInetUtil.INSTANCE.ipv6PrefixFor(ipv6Address, countBits(bytemask));
165     }
166
167     public static Integer extractPrefix(final Ipv4Prefix ipv4Prefix) {
168         return IetfInetUtil.INSTANCE.splitIpv4Prefix(ipv4Prefix).getValue();
169     }
170
171     public static Integer extractPrefix(final Ipv6Prefix ipv6Prefix) {
172         return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
173     }
174
175     public static Integer extractPrefix(final Ipv4Address ipv4Prefix) {
176         return IPV4_ADDRESS_LENGTH;
177     }
178
179     public static Integer extractPrefix(final Ipv6Address ipv6Prefix) {
180         return 128;
181     }
182
183     /*
184      * BIG FAT WARNING!!!
185      * Read all of the following before you touch any v6 code or decide to
186      * optimize it by invoking a "simple" Guava call
187      *
188      * Java IPv6 is fundamentally broken and Google libraries do not fix it.
189      * 1. Java will allways implicitly rewrite v4 mapped into v6 as a v4 address
190      *      and there is absolutely no way to override this behaviour
191      * 2. Guava libraries cannot parse non-canonical IPv6. They will throw an
192      *      exception. Even if they did, they re-use the same broken java code
193      *      underneath.
194      *
195      * This is why we have to parse v6 by ourselves.
196      *
197      * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
198      *
199      * The original BSD code is licensed under standard BSD license. While we
200      * are not obliged to provide an attribution, credit where credit is due.
201      * As far as why it is similar to Sun's sun.net.util please ask Sun why
202      * their code has the same variable names, comments and code flow.
203      *
204      */
205
206
207      /**
208      * Convert Ipv6Address object to a valid Canonical v6 address in byte format
209      *
210      * @param ipv6Address - v6 Address object
211      * @return - byte array of size 16. Last byte contains netmask
212      */
213
214
215     public static byte[] canonicalBinaryV6Address(final Ipv6Address ipv6Address) {
216         /*
217          * Do not modify this routine to take direct strings input!!!
218          * Key checks have been removed based on the assumption that
219          * the input is validated via regexps in Ipv6Prefix()
220          */
221
222         String [] address =  (ipv6Address.getValue()).split("%");
223
224         int colonp;
225         char ch;
226         boolean saw_xdigit;
227
228         /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
229
230         int val;
231
232         char[] src = address[0].toCharArray();
233
234         byte[] dst = new byte[INADDR6SZ];
235
236         int src_length = src.length;
237
238         colonp = -1;
239         int i = 0, j = 0;
240
241         /* Leading :: requires some special handling. */
242
243         /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
244          * We will derive our code from BSD. Shakespear always sounds better
245          * in original Clingon. So does Dilbert.
246          */
247
248         if (src[i] == ':') {
249             Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
250         }
251
252         int curtok = i;
253         saw_xdigit = false;
254
255
256         val = 0;
257         while (i < src_length) {
258             ch = src[i++];
259             int chval = Character.digit(ch, 16);
260
261             /* Business as usual - ipv6 address digit.
262              * We can remove all checks from the original BSD code because
263              * the regexp has already verified that we are not being fed
264              * anything bigger than 0xffff between the separators.
265              */
266
267             if (chval != -1) {
268                 val <<= 4;
269                 val |= chval;
270                 saw_xdigit = true;
271                 continue;
272             }
273
274             /* v6 separator */
275
276             if (ch == ':') {
277                 curtok = i;
278                 if (!saw_xdigit) {
279                     /* no need to check separator position validity - regexp does that */
280                     colonp = j;
281                     continue;
282                 }
283
284                 /* removed overrun check - the regexp checks for valid data */
285
286                 dst[j++] = (byte) ((val >>> 8) & 0xff);
287                 dst[j++] = (byte) (val & 0xff);
288                 saw_xdigit = false;
289                 val = 0;
290                 continue;
291             }
292
293             /* frankenstein - v4 attached to v6, mixed notation */
294
295             if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
296
297                 /* this has passed the regexp so it is fairly safe to parse it
298                  * straight away. As v4 addresses do not suffer from the same
299                  * defficiencies as the java v6 implementation we can invoke it
300                  * straight away and be done with it
301                  */
302
303                 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
304
305                 InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
306
307                 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
308                 System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
309                 j += INADDR4SZ;
310
311                 saw_xdigit = false;
312                 break;
313             }
314             /* removed parser exit on invalid char - no need to do it, regexp checks it */
315         }
316         if (saw_xdigit) {
317             Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
318             dst[j++] = (byte) ((val >> 8) & 0xff);
319             dst[j++] = (byte) (val & 0xff);
320         }
321
322         if (colonp != -1) {
323             int n = j - colonp;
324
325             Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
326             for (i = 1; i <= n; i++) {
327                 dst[INADDR6SZ - i] = dst[colonp + n - i];
328                 dst[colonp + n - i] = 0;
329             }
330             j = INADDR6SZ;
331         }
332
333         Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
334
335         return dst;
336     }
337
338     public static String byteArrayV6AddressToString (final byte [] _binary_form) throws UnknownHostException{
339         /* DO NOT DIY!!! - InetAddresses will actually print correct canonical
340          * zero compressed form.
341          */
342         return InetAddresses.toAddrString(InetAddress.getByAddress(_binary_form));
343     }
344
345     private static int nextNibble(final int mask) {
346         if (mask <= 0) {
347             return 0;
348         }
349         if (mask > 8) {
350             return 0xff;
351         }
352         return 0xff << (8 - mask);
353     }
354
355     /**
356      * Convert Ipv6Prefix object to a valid Canonical v6 prefix in byte format
357      *
358      * @param ipv6Prefix - v6 prefix object
359      * @return - byte array of size 16 + 1. Last byte contains netmask
360      */
361     public static byte[] canonicalBinaryV6Prefix(final Ipv6Prefix ipv6Prefix) {
362         /*
363          * Do not modify this routine to take direct strings input!!!
364          * Key checks have been removed based on the assumption that
365          * the input is validated via regexps in Ipv6Prefix()
366          */
367
368         int mask = 128;
369
370         String [] address = null;
371
372         boolean valid = true;
373
374         address =  (ipv6Prefix.getValue()).split("/");
375         try {
376             mask = Integer.parseInt(address[1]);
377             if (mask > 128) {
378                 valid = false;
379             }
380         } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
381             valid = false;
382         }
383
384         Preconditions.checkArgument(valid, "Supplied netmask in %s is invalid", ipv6Prefix.getValue());
385
386
387         int colonp;
388         char ch;
389         boolean saw_xdigit;
390
391         /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
392
393         int val;
394
395         char[] src = address[0].toCharArray();
396
397         byte[] dst = new byte[INADDR6SZ + 1];
398
399         int m = mask;
400
401         int src_length = src.length;
402
403         colonp = -1;
404         int i = 0, j = 0;
405
406         /* Leading :: requires some special handling. */
407
408         /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
409          * We will derive our code from BSD. Shakespear always sounds better
410          * in original Clingon. So does Dilbert.
411          */
412
413         if (src[i] == ':') {
414             Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
415         }
416
417         int curtok = i;
418         saw_xdigit = false;
419
420
421         val = 0;
422         while (i < src_length) {
423             ch = src[i++];
424             int chval = Character.digit(ch, 16);
425
426             /* Business as usual - ipv6 address digit.
427              * We can remove all checks from the original BSD code because
428              * the regexp has already verified that we are not being fed
429              * anything bigger than 0xffff between the separators.
430              */
431
432             if (chval != -1) {
433                 val <<= 4;
434                 val |= chval;
435                 saw_xdigit = true;
436                 continue;
437             }
438
439             /* v6 separator */
440
441             if (ch == ':') {
442                 curtok = i;
443                 if (!saw_xdigit) {
444                     /* no need to check separator position validity - regexp does that */
445                     colonp = j;
446                     continue;
447                 }
448
449                 /* removed overrun check - the regexp checks for valid data */
450
451                 saw_xdigit = false;
452
453                 if (m < 0) {
454                     /* stop parsing if we are past the mask */
455                     break;
456                 }
457
458                 dst[j] = (byte) ((val >> 8) & nextNibble(m)); j++; m = m - 8;
459
460                 if (m < 0) {
461                     /* stop parsing if we are past the mask */
462                     break;
463                 }
464
465                 dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
466
467                 val = 0;
468                 continue;
469             }
470
471             /* frankenstein - v4 attached to v6, mixed notation */
472
473             if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
474
475                 /* this has passed the regexp so it is fairly safe to parse it
476                  * straight away. As v4 addresses do not suffer from the same
477                  * defficiencies as the java v6 implementation we can invoke it
478                  * straight away and be done with it
479                  */
480
481                 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
482
483                 InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
484
485                 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
486                 System.arraycopy(_inet_form.getAddress(), 0, dst, j, INADDR4SZ);
487                 j +=  INADDR4SZ;
488
489                 saw_xdigit = false;
490                 break;
491             }
492             /* removed parser exit on ivalid char - no need to do it, regexp checks it */
493         }
494         if (saw_xdigit) {
495             Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
496             dst[j] = (byte) ((val >> 8) & nextNibble(m)) ; j++; m = m - 8;
497             dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
498         }
499
500         if ((j < INADDR6SZ) && (m < 0)) {
501             /* past the mask */
502             for (i = j; i < INADDR6SZ; i++) {
503                 dst[i] = 0;
504             }
505         } else {
506             /* normal parsing */
507             if (colonp != -1) {
508                 int n = j - colonp;
509
510                 Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
511                 for (i = 1; i <= n; i++) {
512                     dst[INADDR6SZ - i] = dst[colonp + n - i];
513                     dst[colonp + n - i] = 0;
514                 }
515                 j = INADDR6SZ;
516             }
517             Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
518         }
519
520         dst[INADDR6SZ] = (byte) mask;
521         return dst;
522     }
523
524     /**
525      * Print a v6 prefix in byte array + 1 notation
526      * @param _binary_form - prefix, in byte [] form, last byte is netmask
527      * @return string of v6 prefix
528      * @throws UnknownHostException unknown host exception
529      */
530     public static String byteArrayV6PrefixToString(final byte [] _binary_form) throws UnknownHostException {
531         /* NO DIY!!! - InetAddresses will actually print correct canonical
532          * zero compressed form
533          */
534         StringBuilder sb = new StringBuilder();
535         /* Yang RFC specifies that the normalized form is RFC 5952, note - java
536          * core type is not RFC compliant, guava is.
537          */
538         sb.append(
539             InetAddresses.toAddrString(
540                 InetAddress.getByAddress(
541                     Arrays.copyOf(_binary_form, INADDR6SZ)
542                 )
543             )
544         );
545         sb.append('/');
546         sb.append(_binary_form[INADDR6SZ] & 0xff);
547         return sb.toString();
548     }
549
550     private static int ipv6PrefixByteArrayOffset(final int mask) {
551         if (mask < 0) {
552             return 0;
553         }
554
555         final int ret = mask * INADDR6SZ;
556         if (ret < PREFIX_BYTEARRAYS.length) {
557             return ret;
558         } else {
559             return PREFIX_BYTEARRAYS.length - INADDR6SZ;
560         }
561     }
562
563     /**
564      * Canonicalize a v6 prefix while in binary form
565      *
566      * @param prefix - prefix, in byte [] form
567      * @param mask - mask - number of bits
568      */
569     public static void canonicalizeIpv6Prefix(final byte [] prefix, final int mask) {
570         final int offset = ipv6PrefixByteArrayOffset(mask);
571
572         for (int i = 0; i < INADDR6SZ; i++) {
573             prefix[i] &= PREFIX_BYTEARRAYS[offset + i];
574         }
575     }
576
577     public static byte[] convertIpv6PrefixToByteArray(final int prefix) {
578         final int offset = ipv6PrefixByteArrayOffset(prefix);
579
580         return Arrays.copyOfRange(PREFIX_BYTEARRAYS, offset, offset + INADDR6SZ);
581     }
582
583     public static Ipv6Address extractIpv6Address(final Ipv6Prefix ipv6Prefix) {
584         return IetfInetUtil.INSTANCE.ipv6AddressFrom(ipv6Prefix);
585     }
586
587     public static Integer extractIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
588         return IetfInetUtil.INSTANCE.splitIpv6Prefix(ipv6Prefix).getValue();
589     }
590
591     public static int countBits(final byte[] mask) {
592         int netmask = 0;
593         for (byte b : mask) {
594             netmask += Integer.bitCount(UnsignedBytes.toInt(b));
595         }
596         return netmask;
597     }
598
599     public static final byte[] convertArbitraryMaskToByteArray(DottedQuad mask) {
600         String maskValue;
601         if (mask != null && mask.getValue() != null){
602            maskValue  = mask.getValue();
603         }
604         else {
605             maskValue = DEFAULT_ARBITRARY_BIT_MASK;
606         }
607         InetAddress maskInIpFormat = null;
608         try {
609             maskInIpFormat = InetAddress.getByName(maskValue);
610         } catch (UnknownHostException e) {
611             LOG.error ("Failed to resolve the ip address of the mask",e);
612         }
613         byte[] bytes = maskInIpFormat.getAddress();
614         return bytes;
615     }
616
617     public static boolean isArbitraryBitMask(byte[] byteMask) {
618         if (byteMask == null) {
619             return false;
620         }
621         else {
622             ArrayList<Integer> integerMaskArrayList = new ArrayList<Integer>();
623             String maskInBits;
624             // converting byte array to bits
625             maskInBits = new BigInteger(1, byteMask).toString(2);
626             ArrayList<String> stringMaskArrayList = new ArrayList<String>(Arrays.asList(maskInBits.split("(?!^)")));
627             for(String string:stringMaskArrayList){
628                 integerMaskArrayList.add(Integer.parseInt(string));
629             }
630             return checkArbitraryBitMask(integerMaskArrayList);
631         }
632     }
633
634     private static boolean checkArbitraryBitMask(ArrayList<Integer> arrayList) {
635         // checks 0*1* case - Leading zeros in arrayList are truncated
636         if(arrayList.size()>0 && arrayList.size()<32) {
637             return true;
638         }
639         //checks 1*0*1 case
640         else {
641             for(int i=0; i<arrayList.size()-1;i++) {
642                 if(arrayList.get(i) ==0 && arrayList.get(i+1) == 1) {
643                     return true;
644                 }
645             }
646         }
647         return false;
648     }
649 }