content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You under the Apache License, Version 2.0
   *  (the "License"); you may not use this file except in compliance with
   *  the License.  You may obtain a copy of the License at
   *
   *      https://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  package org.apache.ivy.osgi.obr.xml;
  
  import java.text.ParseException;
  
  import org.apache.ivy.osgi.core.BundleInfo;
  import org.apache.ivy.osgi.core.BundleRequirement;
  import org.apache.ivy.osgi.filter.AndFilter;
  import org.apache.ivy.osgi.filter.CompareFilter;
  import org.apache.ivy.osgi.filter.CompareFilter.Operator;
  import org.apache.ivy.osgi.filter.NotFilter;
  import org.apache.ivy.osgi.filter.OSGiFilter;
  import org.apache.ivy.osgi.util.Version;
  import org.apache.ivy.osgi.util.VersionRange;
  
  public class RequirementAdapter {
  
      private Version startVersion = null;
  
      private boolean startExclusive = false;
  
      private Version endVersion = null;
  
      private boolean endExclusive = false;
  
      private String type = null;
  
      private String name = null;
  
      public static void adapt(BundleInfo info, Requirement requirement)
              throws UnsupportedFilterException, ParseException {
          RequirementAdapter adapter = new RequirementAdapter();
          adapter.extractFilter(requirement.getFilter());
          adapter.adapt(info, requirement.isOptional());
      }
  
      private void extractFilter(OSGiFilter filter) throws UnsupportedFilterException {
          if (filter instanceof AndFilter) {
              AndFilter andFilter = (AndFilter) filter;
              for (OSGiFilter subFilter : andFilter.getSubFilters()) {
                  extractFilter(subFilter);
              }
          } else if (filter instanceof CompareFilter) {
              CompareFilter compareFilter = ((CompareFilter) filter);
              parseCompareFilter(compareFilter, false);
          } else if (filter instanceof NotFilter) {
              NotFilter notFilter = ((NotFilter) filter);
              if (notFilter.getSubFilter() instanceof CompareFilter) {
                  CompareFilter compareFilter = ((CompareFilter) notFilter.getSubFilter());
                  parseCompareFilter(compareFilter, true);
              }
          } else {
              throw new UnsupportedFilterException("Unsupported filter: "
                      + filter.getClass().getName());
          }
      }
  
      private void adapt(BundleInfo info, boolean optional) throws ParseException {
          VersionRange range = getVersionRange();
          String resolution = optional ? "optional" : null;
          if (type == null) {
              throw new ParseException("No requirement actually specified", 0);
          }
          BundleRequirement requirement = new BundleRequirement(type, name, range, resolution);
          info.addRequirement(requirement);
          if (BundleInfo.EXECUTION_ENVIRONMENT_TYPE.equals(type)) {
              info.addExecutionEnvironment(name);
          }
      }
  
      private VersionRange getVersionRange() {
          VersionRange range = null;
          if (startVersion != null || endVersion != null) {
              range = new VersionRange(startExclusive, startVersion, endExclusive, endVersion);
          }
          return range;
      }
  
      private void parseCompareFilter(CompareFilter compareFilter, boolean not)
              throws UnsupportedFilterException {
          String att = compareFilter.getLeftValue();
          if ("symbolicname".equals(att)) {
              att = BundleInfo.BUNDLE_TYPE;
          }
          switch (att) {
              case BundleInfo.BUNDLE_TYPE:
              case BundleInfo.EXECUTION_ENVIRONMENT_TYPE:
              case BundleInfo.PACKAGE_TYPE:
              case BundleInfo.SERVICE_TYPE:
                  if (not) {
                      throw new UnsupportedFilterException(
                              "Not filter on requirement comparison is not supported");
                  }
                  if (compareFilter.getOperator() != Operator.EQUALS) {
                      throw new UnsupportedFilterException(
                              "Filtering is only supported with the operator '='");
                  }
                  if (type != null) {
                      throw new UnsupportedFilterException(
                              "Multiple requirement type are not supported");
                  }
                  type = att;
                  name = compareFilter.getRightValue();
                  break;
              case "version":
                  Version version = new Version(compareFilter.getRightValue());
                  Operator operator = compareFilter.getOperator();
                  if (not) {
                      switch (operator) {
                          case EQUALS:
                              throw new UnsupportedFilterException(
                                      "Not filter on equals comparison is not supported");
                          case GREATER_OR_EQUAL:
                              operator = Operator.LOWER_THAN;
                              break;
                          case GREATER_THAN:
                              operator = Operator.LOWER_OR_EQUAL;
                              break;
                          case LOWER_OR_EQUAL:
                              operator = Operator.GREATER_THAN;
                              break;
                          case LOWER_THAN:
                              operator = Operator.GREATER_OR_EQUAL;
                              break;
                      }
                  }
                  switch (operator) {
                      case EQUALS:
                          if (startVersion != null || endVersion != null) {
                              throw new UnsupportedFilterException(
                                      "Multiple version matching is not supported");
                          }
                          startVersion = version;
                          startExclusive = false;
                          endVersion = version;
                          endExclusive = false;
                          break;
                      case GREATER_OR_EQUAL:
                          if (startVersion != null) {
                              throw new UnsupportedFilterException(
                                      "Multiple version matching is not supported");
                          }
                          startVersion = version;
                          startExclusive = false;
                          break;
                      case GREATER_THAN:
                          if (startVersion != null) {
                              throw new UnsupportedFilterException(
                                      "Multiple version matching is not supported");
                          }
                          startVersion = version;
                          startExclusive = true;
                          break;
                      case LOWER_OR_EQUAL:
                          if (endVersion != null) {
                              throw new UnsupportedFilterException(
                                      "Multiple version matching is not supported");
                          }
                          endVersion = version;
                          endExclusive = false;
                          break;
                      case LOWER_THAN:
                          if (endVersion != null) {
                              throw new UnsupportedFilterException(
                                      "Multiple version matching is not supported");
                          }
                          endVersion = version;
                          endExclusive = true;
                          break;
                  }
                  break;
              default:
                  throw new UnsupportedFilterException("Unsupported attribute: " + att);
          }
  
      }
  }
  