/*
 * 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
 *
 *   http://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 WARRANTIESOR 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.aries.application.runtime.framework;

import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
import static org.apache.aries.application.utils.AppConstants.LOG_EXCEPTION;
import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;

import java.util.ArrayList;
import java.util.List;

import org.apache.aries.application.management.AriesApplication;
import org.apache.aries.application.management.BundleFramework;
import org.apache.aries.application.management.BundleRepository.BundleSuggestion;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.osgi.service.framework.CompositeBundle;
import org.osgi.service.packageadmin.PackageAdmin;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BundleFrameworkImpl implements BundleFramework
{
  private static final Logger LOGGER = LoggerFactory.getLogger(BundleFrameworkImpl.class);

  List<Bundle> _bundles;
  CompositeBundle _compositeBundle;

  ServiceTracker _packageAdminTracker;

  BundleFrameworkImpl(CompositeBundle cb)
  {
    _compositeBundle = cb;
    _bundles = new ArrayList<Bundle>();
  }

  public void init() throws BundleException
  {
    if (_compositeBundle.getCompositeFramework().getState() != Framework.ACTIVE)
    {
      _compositeBundle.start(Bundle.START_ACTIVATION_POLICY);
  
      _packageAdminTracker = new ServiceTracker(_compositeBundle.getBundleContext(),
          PackageAdmin.class.getName(), null);
      _packageAdminTracker.open();
    }
  }

  public void close() throws BundleException
  {
    /**
     * TODO: Remove this work-around code 
     * 
     * Workaround for IllegalArgumentException during PackagePermission check
     * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=298894
     */
    BundleContext ctx = _compositeBundle.getBundleContext();
    ServiceReference ref = ctx.getServiceReference(PackageAdmin.class.getName());
    if (ref != null) {
      try {
        PackageAdmin pa = (PackageAdmin) ctx.getService(ref);
        pa.refreshPackages(null);
      } finally {
        ctx.ungetService(ref);
      }
    }

    // close out packageadmin service tracker
    if (_packageAdminTracker != null) {
      try {
        _packageAdminTracker.close();
      } catch (IllegalStateException ise) {
        // Ignore this error because this can happen when we're trying to close the tracker on a
        // framework that has closed/is closing.
      }
    }

    _compositeBundle.stop();
  }

  public void start(Bundle b) throws BundleException
  {
    if (b.getState() != Bundle.ACTIVE && !isFragment(b)) 
      b.start(Bundle.START_ACTIVATION_POLICY);
  }

  public void stop(Bundle b) throws BundleException
  {
    b.stop();
  }

  public Bundle getFrameworkBundle()
  {
    return _compositeBundle;
  }

  public BundleContext getIsolatedBundleContext()
  {
    return _compositeBundle.getCompositeFramework().getBundleContext();
  }

  public List<Bundle> getBundles()
  {
    return _bundles;
  }

  /**
   * This method uses the PackageAdmin service to identify if a bundle
   * is a fragment.
   * @param b
   * @return
   */
  private boolean isFragment(Bundle b)
  {
    LOGGER.debug(LOG_ENTRY, "isFragment", new Object[] { b });

    PackageAdmin admin = null;
    boolean isFragment = false;

    try {
      if (_packageAdminTracker != null) {
        admin = (PackageAdmin) _packageAdminTracker.getService();
        if (admin != null) {
          isFragment = (admin.getBundleType(b) == PackageAdmin.BUNDLE_TYPE_FRAGMENT);
        }
      }
    } catch (RuntimeException re) {
      LOGGER.debug(LOG_EXCEPTION, re);
    }

    LOGGER.debug(LOG_EXIT, "isFragment", new Object[] { Boolean.valueOf(isFragment) });

    return isFragment;
  }

  public Bundle install(BundleSuggestion suggestion, AriesApplication app) throws BundleException
  {
    Bundle installedBundle = suggestion.install(getIsolatedBundleContext(), app);
    _bundles.add(installedBundle);
    
    return installedBundle;
  }

  public void uninstall(Bundle b) throws BundleException
  {
    b.uninstall();
    _bundles.remove(b);
  }
}

@@ -1754,16 +1754,94 @@
 ctory;%0A%0A
+import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader.Array;%0A%0A
 public c
@@ -2637,555 +2637,8 @@
   %7B%0A
-    /**%0A     * TODO: Remove this work-around code %0A     * %0A     * Workaround for IllegalArgumentException during PackagePermission check%0A     * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=298894%0A     */%0A    BundleContext ctx = _compositeBundle.getBundleContext();%0A    ServiceReference ref = ctx.getServiceReference(PackageAdmin.class.getName());%0A    if (ref != null) %7B%0A      try %7B%0A        PackageAdmin pa = (PackageAdmin) ctx.getService(ref);%0A        pa.refreshPackages(null);%0A      %7D finally %7B%0A        ctx.ungetService(ref);%0A      %7D%0A    %7D%0A%0A
     
@@ -4633,14 +4633,434 @@
 ove(b);%0A
+    %0A    /* Call PackageAdmin.refreshPackages() after uninstall %0A%09 * to clean out a partially removed bundle. Just to be sure. %0A%09 */ %0A    PackageAdmin admin = null;%0A    try %7B%0A      if (_packageAdminTracker != null) %7B%0A        admin = (PackageAdmin) _packageAdminTracker.getService();%0A        admin.refreshPackages(new Bundle%5B%5D%7Bb%7D);%0A      %7D%0A    %7D catch (RuntimeException re) %7B%0A      LOGGER.debug(LOG_EXCEPTION, re);%0A    %7D%0A
   %7D%0A%7D%0A

Remove workaround; call refreshPackages() on each bundle as it's uninstalled.