/*******************************************************************************
* Copyright (c) 2013-2015 Pivotal, Inc.
* 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
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.core;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.expressions.PropertyTester;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.osgi.framework.Bundle;
import org.osgi.framework.Version;
import org.osgi.framework.VersionRange;
import org.springframework.ide.eclipse.boot.util.Log;
import org.springsource.ide.eclipse.commons.internal.core.CorePlugin;
/**
* @author Kris De Volder
*/
public class BootPropertyTester extends PropertyTester {
private static final Pattern JAR_VERSION_REGEXP = Pattern.compile(".*\\-([^.]+\\.[^.]+\\.[^.]+\\.[^.]+)\\.jar");
public BootPropertyTester() {
// TODO Auto-generated constructor stub
}
//@Override
public boolean test(Object rsrc, String property, Object[] args, Object expectedValue) {
if (expectedValue==null) {
expectedValue = true;
}
// System.out.println(">>> BootPropertyTester");
// System.out.println(" rsrc = "+rsrc);
// System.out.println(" property = "+property);
// System.out.println(" expectedValue = "+expectedValue);
if (rsrc instanceof IProject && "isBootProject".equals(property)) {
return expectedValue.equals(isBootProject((IProject)rsrc));
}
if (rsrc instanceof IResource && "isBootResource".equals(property)) {
return expectedValue.equals(isBootResource((IResource) rsrc));
}
return false;
}
public static boolean isDevtoolsJar(IClasspathEntry e) {
if (e.getEntryKind()==IClasspathEntry.CPE_LIBRARY) {
IPath path = e.getPath();
String name = path.lastSegment();
return name.endsWith(".jar") && name.startsWith("spring-boot-devtools");
}
return false;
}
public static boolean hasDevtools(IProject p) {
try {
if (p!=null && p.isAccessible()) {
IJavaProject jp = JavaCore.create(p);
if (jp.exists()) {
IClasspathEntry[] classpath = jp.getResolvedClasspath(true);
if (classpath!=null) {
for (IClasspathEntry e : classpath) {
if (BootPropertyTester.isDevtoolsJar(e)) {
return true;
}
}
}
}
}
} catch (Exception e) {
Log.log(e);
}
return false;
}
public static boolean isBootProject(IProject project) {
if (project==null || ! project.isAccessible()) {
return false;
}
try {
if (project.hasNature(JavaCore.NATURE_ID)) {
if (!isExcludedProject(project)) {
IJavaProject jp = JavaCore.create(project);
IClasspathEntry[] classpath = jp.getResolvedClasspath(true);
//Look for a 'spring-boot' jar or project entry
for (IClasspathEntry e : classpath) {
if (isBootJar(e) || isBootProject(e)) {
return true;
}
}
}
}
} catch (Exception e) {
CorePlugin.log(e);
}
return false;
}
private static boolean isExcludedProject(IProject project) {
Pattern exclusion = BootPreferences.getInstance().getProjectExclusion();
return exclusion.matcher(project.getName()).matches();
}
/**
* @return whether given resource is either Spring Boot IProject or nested inside one.
*/
public static boolean isBootResource(IResource rsrc) {
if (rsrc==null || ! rsrc.isAccessible()) {
return false;
}
boolean result = isBootProject(rsrc.getProject());
return result;
}
public static boolean isBootProject(IClasspathEntry e) {
if (e.getEntryKind()==IClasspathEntry.CPE_PROJECT) {
IPath path = e.getPath();
String name = path.lastSegment();
return name.startsWith("spring-boot");
}
return false;
}
public static boolean isBootJar(IClasspathEntry e) {
if (e.getEntryKind()==IClasspathEntry.CPE_LIBRARY) {
IPath path = e.getPath();
String name = path.lastSegment();
return name.endsWith(".jar") && name.startsWith("spring-boot");
}
return false;
}
/**
* Attempt to determine spring-boot version from project's classpath, in a form that
* is easy to compare to version ranges. May return null if the version couldn't be
* determined.
*/
public static Version getBootVersion(IProject p) {
try {
if (p.isAccessible() && p.hasNature(JavaCore.NATURE_ID)) {
IJavaProject jp = JavaCore.create(p);
IClasspathEntry[] cp = jp.getResolvedClasspath(true);
for (IClasspathEntry e : cp) {
if (isBootJar(e)) {
String version = getJarVersion(e);
if (version!=null) {
return new Version(version);
}
}
}
}
} catch (Exception error) {
BootActivator.log(error);
}
return null;
}
private static String getJarVersion(IClasspathEntry e) {
String name = e.getPath().lastSegment();
//Example: spring-boot-starter-web-1.2.3.RELEASE.jar
//Pattern regexp = Pattern.compile(".*\\-([^.]+\\.[^.]+\\.[^.]+\\.[^.]+)\\.jar");
Pattern regexp = JAR_VERSION_REGEXP;
Matcher matcher = regexp.matcher(name);
if (matcher.matches()) {
String versionStr = matcher.group(1);
return versionStr;
}
return null;
}
public static boolean supportsLifeCycleManagement(IProject project) {
Version version = BootPropertyTester.getBootVersion(project);
if (version!=null) {
return new VersionRange("1.3.0").includes(version);
}
return false;
}
/**
* this is a workaround for an initialization issue around m2e
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=479245
*
* this workaround tries to avoid very early m2e.jdt activation
* and therefore tries to reduce the likelihood of running into
* the issue.
*/
public static boolean workaroundMavenBundleInitializationIssue(IProject project) {
try {
if (project.hasNature("org.eclipse.m2e.core.maven2Nature")) {
Bundle bundle = Platform.getBundle("org.eclipse.m2e.jdt");
if (bundle != null) {
if (bundle.getState() != Bundle.ACTIVE) {
return true;
}
}
}
} catch (CoreException e) {
}
return false;
}
}