001/** 002 * Copyright 2010-2016 Boxfuse GmbH 003 * <p/> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p/> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p/> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.avaje.classpath.scanner.internal.scanner.classpath; 017 018import org.osgi.framework.Bundle; 019import org.osgi.framework.FrameworkUtil; 020 021import java.io.IOException; 022import java.net.URL; 023import java.util.Enumeration; 024import java.util.Set; 025import java.util.TreeSet; 026import java.util.regex.Matcher; 027import java.util.regex.Pattern; 028 029/** 030 * OSGi specific scanner that performs the migration search in 031 * the current bundle's classpath. 032 * 033 * <p> 034 * The resources that this scanner returns can only be loaded if 035 * Flyway's ClassLoader has access to the bundle that contains the migrations. 036 * </p> 037 */ 038public class OsgiClassPathLocationScanner implements ClassPathLocationScanner { 039 040 //Felix and Equinox "host" resource url pattern starts with bundleId, which is 041 // long according osgi core specification 042 private static final Pattern bundleIdPattern = Pattern.compile("^\\d+"); 043 044 public Set<String> findResourceNames(String location, URL locationUrl) throws IOException { 045 Set<String> resourceNames = new TreeSet<String>(); 046 047 Bundle bundle = getTargetBundleOrCurrent(FrameworkUtil.getBundle(getClass()), locationUrl); 048 @SuppressWarnings({"unchecked"}) 049 Enumeration<URL> entries = bundle.findEntries(locationUrl.getPath(), "*", true); 050 051 if (entries != null) { 052 while (entries.hasMoreElements()) { 053 URL entry = entries.nextElement(); 054 String resourceName = getPathWithoutLeadingSlash(entry); 055 056 resourceNames.add(resourceName); 057 } 058 } 059 060 return resourceNames; 061 } 062 063 private Bundle getTargetBundleOrCurrent(Bundle currentBundle, URL locationUrl) { 064 try { 065 Bundle targetBundle = currentBundle.getBundleContext().getBundle(getBundleId(locationUrl.getHost())); 066 return targetBundle != null ? targetBundle : currentBundle; 067 } catch (Exception e) { 068 return currentBundle; 069 } 070 } 071 072 private long getBundleId(String host) { 073 final Matcher matcher = bundleIdPattern.matcher(host); 074 if (matcher.find()) { 075 return Double.valueOf(matcher.group()).longValue(); 076 } 077 throw new IllegalArgumentException("There's no bundleId in passed URL"); 078 } 079 080 private String getPathWithoutLeadingSlash(URL entry) { 081 final String path = entry.getPath(); 082 083 return path.startsWith("/") ? path.substring(1) : path; 084 } 085}