gt:         Status status = config.isValid();
context: /*
   * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
   *
   * This program and the accompanying materials are made available under the
   * terms of the Eclipse Public License v1.0 which accompanies this distribution,
   * and is available at http://www.eclipse.org/legal/epl-v10.html
   */
  
  package org.opendaylight.controller.forwarding.staticrouting.internal;
  
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.net.Inet4Address;
  import java.net.InetAddress;
  import java.nio.ByteBuffer;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Dictionary;
  import java.util.EnumSet;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Set;
  import java.util.Timer;
  import java.util.TimerTask;
  import java.util.concurrent.Callable;
  import java.util.concurrent.ConcurrentMap;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  import java.util.concurrent.Future;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  
  import org.apache.felix.dm.Component;
  import org.opendaylight.controller.clustering.services.CacheConfigException;
  import org.opendaylight.controller.clustering.services.CacheExistException;
  import org.opendaylight.controller.clustering.services.IClusterContainerServices;
  import org.opendaylight.controller.clustering.services.IClusterServices;
  import org.opendaylight.controller.configuration.ConfigurationObject;
  import org.opendaylight.controller.configuration.IConfigurationContainerAware;
  import org.opendaylight.controller.configuration.IConfigurationContainerService;
  import org.opendaylight.controller.forwarding.staticrouting.IForwardingStaticRouting;
  import org.opendaylight.controller.forwarding.staticrouting.IStaticRoutingAware;
  import org.opendaylight.controller.forwarding.staticrouting.StaticRoute;
  import org.opendaylight.controller.forwarding.staticrouting.StaticRouteConfig;
  import org.opendaylight.controller.hosttracker.HostIdFactory;
  import org.opendaylight.controller.hosttracker.IHostId;
  import org.opendaylight.controller.hosttracker.IfIptoHost;
  import org.opendaylight.controller.hosttracker.IfNewHostNotify;
  import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
  import org.opendaylight.controller.sal.utils.IObjectReader;
  import org.opendaylight.controller.sal.utils.Status;
  import org.opendaylight.controller.sal.utils.StatusCode;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * Static Routing feature provides the bridge between SDN and Non-SDN networks.
   */
  public class StaticRoutingImplementation implements IfNewHostNotify, IForwardingStaticRouting, IObjectReader,
          IConfigurationContainerAware {
      private static Logger log = LoggerFactory.getLogger(StaticRoutingImplementation.class);
      private static final String STATIC_ROUTES_FILE_NAME = "staticRouting.conf";
      ConcurrentMap<String, StaticRoute> staticRoutes;
      ConcurrentMap<String, StaticRouteConfig> staticRouteConfigs;
      private IfIptoHost hostTracker;
      private Timer gatewayProbeTimer;
      private IClusterContainerServices clusterContainerService = null;
      private IConfigurationContainerService configurationService;
      private Set<IStaticRoutingAware> staticRoutingAware = Collections
              .synchronizedSet(new HashSet<IStaticRoutingAware>());
      private ExecutorService executor;
  
      void setStaticRoutingAware(IStaticRoutingAware s) {
          if (this.staticRoutingAware != null) {
              this.staticRoutingAware.add(s);
          }
      }
  
      void unsetStaticRoutingAware(IStaticRoutingAware s) {
          if (this.staticRoutingAware != null) {
              this.staticRoutingAware.remove(s);
          }
      }
  
      public void setHostTracker(IfIptoHost hostTracker) {
          log.debug("Setting HostTracker");
          this.hostTracker = hostTracker;
      }
  
      public void unsetHostTracker(IfIptoHost hostTracker) {
          if (this.hostTracker == hostTracker) {
              this.hostTracker = null;
          }
      }
  
      public void setConfigurationContainerService(IConfigurationContainerService service) {
          log.trace("Got configuration service set request {}", service);
          this.configurationService = service;
      }
  
      public void unsetConfigurationContainerService(IConfigurationContainerService service) {
          log.trace("Got configuration service UNset request");
          this.configurationService = null;
      }
  
      @Override
      public ConcurrentMap<String, StaticRouteConfig> getStaticRouteConfigs() {
          return staticRouteConfigs;
      }
  
      @Override
      public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
          // Perform the class deserialization locally, from inside the package
          // where the class is defined
          return ois.readObject();
      }
  
  
      private void loadConfiguration() {
          for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, STATIC_ROUTES_FILE_NAME)) {
              addStaticRoute((StaticRouteConfig) conf);
          }
      }
  
      private Status saveConfig() {
          return saveConfigInternal();
      }
  
      public Status saveConfigInternal() {
          Status status = configurationService.persistConfiguration(
                  new ArrayList<ConfigurationObject>(staticRouteConfigs.values()), STATIC_ROUTES_FILE_NAME);
  
          if (status.isSuccess()) {
              return status;
          } else {
              return new Status(StatusCode.INTERNALERROR, "Save failed");
          }
      }
  
      private void allocateCaches() {
          if (this.clusterContainerService == null) {
              log.trace("un-initialized clusterContainerService, can't create cache");
              return;
          }
  
          try {
              clusterContainerService.createCache("forwarding.staticrouting.routes",
                      EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
              clusterContainerService.createCache("forwarding.staticrouting.configs",
                      EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
          } catch (CacheExistException cee) {
              log.error("\nCache already exists - destroy and recreate if needed");
          } catch (CacheConfigException cce) {
              log.error("\nCache configuration invalid - check cache mode");
          }
      }
  
      @SuppressWarnings({ "unchecked" })
      private void retrieveCaches() {
          if (this.clusterContainerService == null) {
              log.warn("un-initialized clusterContainerService, can't retrieve cache");
              return;
          }
  
          staticRoutes = (ConcurrentMap<String, StaticRoute>) clusterContainerService
                  .getCache("forwarding.staticrouting.routes");
          if (staticRoutes == null) {
              log.error("\nFailed to get rulesDB handle");
          }
  
          staticRouteConfigs = (ConcurrentMap<String, StaticRouteConfig>) clusterContainerService
                  .getCache("forwarding.staticrouting.configs");
          if (staticRouteConfigs == null) {
              log.error("\nFailed to get rulesDB handle");
          }
      }
  
      private void notifyStaticRouteUpdate(StaticRoute s, boolean update) {
          if (this.staticRoutingAware != null) {
              log.trace("Invoking StaticRoutingAware listeners");
              synchronized (this.staticRoutingAware) {
                  for (IStaticRoutingAware ra : this.staticRoutingAware) {
                      try {
                          ra.staticRouteUpdate(s, update);
                      } catch (Exception e) {
                          log.error("", e);
                      }
                  }
              }
          }
      }
  
      private class NotifyStaticRouteWorker implements Callable<Object> {
  
          private String name;
          private StaticRoute staticRoute;
          private boolean added;
  
          public NotifyStaticRouteWorker(String name, StaticRoute s, boolean update) {
              this.name = name;
              this.staticRoute = s;
              this.added = update;
          }
  
          @Override
          public Object call() throws Exception {
              if (!added || (staticRoute.getType() == StaticRoute.NextHopType.SWITCHPORT)) {
                  notifyStaticRouteUpdate(staticRoute, added);
              } else {
                  InetAddress nh = staticRoute.getNextHopAddress();
                  // HostTracker hosts db key scheme implementation
                  IHostId id = HostIdFactory.create(nh, null);
                  HostNodeConnector host = hostTracker.hostQuery(id);
                  if (host == null) {
                      log.debug("Next hop {}  is not present, try to discover it", nh.getHostAddress());
                      Future<HostNodeConnector> future = hostTracker.discoverHost(id);
                      if (future != null) {
                          try {
                              host = future.get();
                          } catch (InterruptedException ioe) {
                              log.trace("Thread interrupted {}", ioe);
                          } catch (Exception e) {
                              log.error("", e);
                          }
                      }
                  }
                  if (host != null) {
                      log.debug("Next hop {} is found", nh.getHostAddress());
                      staticRoute.setHost(host);
                      // static route object has changed
                      // put the changed object back in the cache
                      // for it to sync
                      staticRoutes.put(name, staticRoute);
                      notifyStaticRouteUpdate(staticRoute, added);
                  } else {
                      log.debug("Next hop {}  is still not present, try again later", nh.getHostAddress());
                  }
              }
              return null;
          }
      }
  
      private void checkAndUpdateListeners(String name, StaticRoute staticRoute, boolean added) {
          NotifyStaticRouteWorker worker = new NotifyStaticRouteWorker(name, staticRoute, added);
          try {
              executor.submit(worker);
          } catch (Exception e) {
              log.error("got Exception ", e);
          }
      }
  
      private void notifyHostUpdate(HostNodeConnector host, boolean added) {
          if (host == null) {
              return;
          }
          for (Map.Entry<String, StaticRoute> s : staticRoutes.entrySet()) {
              StaticRoute route = s.getValue();
              if (route.getType() == StaticRoute.NextHopType.SWITCHPORT) {
                  continue;
              }
              if (route.getNextHopAddress().equals(host.getNetworkAddress())) {
                  if (added) {
                      route.setHost(host);
                  } else {
                      route.setHost(null);
                  }
                  // static route object has changed
                  // put the changed object back in the cache
                  // for it to sync
                  staticRoutes.put(s.getKey(), route);
                  notifyStaticRouteUpdate(route, added);
              }
          }
      }
  
      @Override
      public void notifyHTClient(HostNodeConnector host) {
          notifyHostUpdate(host, true);
      }
  
      @Override
      public void notifyHTClientHostRemoved(HostNodeConnector host) {
          notifyHostUpdate(host, false);
      }
  
      public boolean isIPv4AddressValid(String cidr) {
          if (cidr == null) {
              return false;
          }
  
          String values[] = cidr.split("/");
          Pattern ipv4Pattern = Pattern
                  .compile("(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])");
          Matcher mm = ipv4Pattern.matcher(values[0]);
          if (!mm.matches()) {
              log.debug("IPv4 source address {} is not valid", cidr);
              return false;
          }
          if (values.length >= 2) {
              int prefix = Integer.valueOf(values[1]);
              if ((prefix < 0) || (prefix > 32)) {
                  log.debug("prefix {} is not valid", prefix);
                  return false;
              }
          }
          return true;
      }
  
      public static short getUnsignedByte(ByteBuffer bb, int position) {
          return ((short) (bb.get(position) & (short) 0xff));
      }
  
      public static int compareByteBuffers(ByteBuffer buf1, ByteBuffer buf2) {
          for (int i = 0; i < buf1.array().length; i++) {
              if (getUnsignedByte(buf1, i) > getUnsignedByte(buf2, i)) {
                  return 1;
              } else if (getUnsignedByte(buf1, i) < getUnsignedByte(buf2, i)) {
                  return -1;
              }
          }
  
          return 0;
      }
  
      @Override
      public StaticRoute getBestMatchStaticRoute(InetAddress ipAddress) {
          ByteBuffer bblongestPrefix = null;
          try {
              bblongestPrefix = ByteBuffer.wrap(InetAddress.getByName("0.0.0.0").getAddress());
          } catch (Exception e) {
              return null;
          }
  
          if (staticRoutes == null) {
              return null;
          }
  
          StaticRoute longestPrefixRoute = null;
          for (StaticRoute s : staticRoutes.values()) {
              InetAddress prefix = s.longestPrefixMatch(ipAddress);
              if ((prefix != null) && (prefix instanceof Inet4Address)) {
                  ByteBuffer bbtmp = ByteBuffer.wrap(prefix.getAddress());
                  if (compareByteBuffers(bbtmp, bblongestPrefix) > 0) {
                      bblongestPrefix = bbtmp;
                      longestPrefixRoute = s;
                  }
              }
          }
          return longestPrefixRoute;
      }
  
      @Override
      public Status addStaticRoute(StaticRouteConfig config) {
  