/*
 * Copyright 2010-2017 Boxfuse GmbH
 *
 * Licensed 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 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.flywaydb.core.internal.util.scanner.classpath.android;

import android.content.Context;
import dalvik.system.DexFile;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.android.ContextHolder;
import org.flywaydb.core.api.logging.Log;
import org.flywaydb.core.api.logging.LogFactory;
import org.flywaydb.core.internal.util.ClassUtils;
import org.flywaydb.core.internal.util.Location;
import org.flywaydb.core.internal.util.scanner.LoadableResource;
import org.flywaydb.core.internal.util.scanner.classpath.ResourceAndClassScanner;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * Class & resource scanner for Android.
 */
public class AndroidScanner implements ResourceAndClassScanner {
    private static final Log LOG = LogFactory.getLog(AndroidScanner.class);

    private final Context context;

    private final ClassLoader classLoader;

    public AndroidScanner(ClassLoader classLoader) {
        this.classLoader = classLoader;
        context = ContextHolder.getContext();
        if (context == null) {
            throw new FlywayException("Unable to scan for Migrations! Context not set. " +
                    "Within an activity you can fix this with org.flywaydb.core.api.android.ContextHolder.setContext(this);");
        }
    }

    public LoadableResource[] scanForResources(Location location, String prefix, String suffix) throws Exception {
        List<LoadableResource> resources = new ArrayList<LoadableResource>();

        String path = location.getPath();
        for (String asset : context.getAssets().list(path)) {
            if (asset.startsWith(prefix) && asset.endsWith(suffix)
                    && (asset.length() > (prefix + suffix).length())) {
                resources.add(new AndroidResource(context.getAssets(), path, asset));
            } else {
                LOG.debug("Filtering out asset: " + asset);
            }
        }

        return resources.toArray(new LoadableResource[resources.size()]);
    }

    public Class<?>[] scanForClasses(Location location, Class<?> implementedInterface) throws Exception {
        String pkg = location.getPath().replace("/", ".");

        List<Class> classes = new ArrayList<Class>();

        DexFile dex = new DexFile(context.getApplicationInfo().sourceDir);
        Enumeration<String> entries = dex.entries();
        while (entries.hasMoreElements()) {
            String className = entries.nextElement();
            if (className.startsWith(pkg)) {
                Class<?> clazz = classLoader.loadClass(className);
                if (Modifier.isAbstract(clazz.getModifiers())) {
                    LOG.debug("Skipping abstract class: " + className);
                    continue;
                }

                if (!implementedInterface.isAssignableFrom(clazz)) {
                    continue;
                }

                ClassUtils.instantiate(className, classLoader);

                classes.add(clazz);
                LOG.debug("Found class: " + className);
            }
        }
        return classes.toArray(new Class<?>[classes.size()]);
    }
}
@@ -2910,16 +2910,55 @@
 le dex =
+ null;%0A%0A        try %7B%0A            dex =
  new Dex
@@ -3011,16 +3011,20 @@
         
+  
+  
 Enumerat
@@ -3068,16 +3068,20 @@
         
+    
 while (e
@@ -3116,24 +3116,28 @@
             
+ 
+   
 String class
@@ -3174,24 +3174,28 @@
             
+   
+ 
 if (classNam
@@ -3211,24 +3211,28 @@
 ith(pkg)) %7B%0A
+    
             
@@ -3298,24 +3298,28 @@
             
+  
+  
 if (Modifier
@@ -3351,24 +3351,28 @@
 fiers())) %7B%0A
+    
             
@@ -3443,32 +3443,36 @@
                 
+ 
+   
 continue;%0A      
@@ -3473,35 +3473,43 @@
                 
-%7D%0A%0A
+    %7D%0A%0A    
                 
@@ -3573,32 +3573,36 @@
                 
+  
+  
 continue;%0A      
@@ -3603,35 +3603,43 @@
                 
-%7D%0A%0A
+    %7D%0A%0A    
                 
@@ -3683,24 +3683,28 @@
 ssLoader);%0A%0A
+    
             
@@ -3735,32 +3735,36 @@
                 
+    
 LOG.debug(%22Found
@@ -3791,34 +3791,42 @@
 e);%0A            
-%7D%0A
+    %7D%0A    
         %7D%0A      
@@ -3811,32 +3811,130 @@
 %7D%0A            %7D%0A
+        %7D finally %7B%0A            if (dex != null) %7B%0A                dex.close();%0A            %7D%0A    
         return c
@@ -3983,11 +3983,22 @@
 %5D);%0A
+        %7D%0A
     %7D%0A%7D
+%0A

Fix on Android platform DexFile resource leak, closing the DexFile instance