/*******************************************************************************
* Copyright (c) 2012 VMware, 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:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.roo.core.internal.model;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.service.resolver.VersionRange;
import org.osgi.framework.Version;
import org.springframework.ide.eclipse.roo.core.RooCoreActivator;
import org.springframework.ide.eclipse.roo.core.model.IRooInstall;
import org.springframework.util.StringUtils;
/**
* Instances of this class represent an installation of Spring Roo.
* @author Christian Dupuis
*/
public class DefaultRooInstall implements IRooInstall {
private final String home;
private boolean isDefault = false;
private final String name;
public static String UNKNOWN_VERSION = "<UNKNOWN VERSION>";
public DefaultRooInstall(String home, String name, boolean isDefault) {
this.home = (home != null && !home.endsWith(File.separator) ? home + File.separator : home);
this.name = name;
this.isDefault = isDefault;
}
public URL[] getClasspath() {
if (!StringUtils.hasLength(home)) {
return new URL[0];
}
Set<URL> urls = new LinkedHashSet<URL>();
File rooHome = new File(home);
if (rooHome.exists()) {
addBootstrapJar(urls, rooHome, "bin");
addBootstrapJar(urls, rooHome, "bundle");
}
return urls.toArray(new URL[urls.size()]);
}
public String getHome() {
return home;
}
public String getName() {
return name;
}
public String getVersion() {
if (home != null) {
return versionInfo();
}
return UNKNOWN_VERSION;
}
public boolean isDefault() {
return isDefault;
}
public IStatus validate() {
// Check if Roo home exists
File home = new File(getHome());
if (!home.exists()) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"Roo installation '%s' points to non-existing path '%s'.", getName(), getHome()));
}
if (!home.isDirectory()) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"Roo installation '%s' does not point to a directory '%s'.", getName(), getHome()));
}
// Check if Roo home is writable
if (!home.canWrite()) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"The Roo installation directory of Roo installation '%s' is not writable.", getName()));
}
// Check that Roo directory structure exists
File bin = new File(home, "bin");
File bundle = new File(home, "bundle");
File conf = new File(home, "conf");
File configProperties = new File(conf, "config.properties");
if (!bin.exists()) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"Roo installation '%s' is missing the 'bin' folder.", getName()));
}
if (!bundle.exists()) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"Roo installation '%s' is missing the 'bundle' folder.", getName()));
}
if (!conf.exists()) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"Roo installation '%s' is missing the 'conf' folder.", getName()));
}
if (!configProperties.exists()) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"Roo installation '%s' is missing the 'conf/config.properties' file.", getName()));
}
if (UNKNOWN_VERSION.equals(getVersion())) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"Cannot determine Roo version for installation '%s'.", getName()));
}
String rawVersion = getVersion();
int i = rawVersion.indexOf(' ');
Version version = Version.parseVersion(rawVersion.substring(0, i));
VersionRange range = new VersionRange(IRooInstall.SUPPORTED_VERSION);
if (!range.isIncluded(version)) {
return new Status(IStatus.ERROR, RooCoreActivator.PLUGIN_ID, String.format(
"Roo installation '%s' of version '%s' is not supported.", getName(), getVersion()));
}
return Status.OK_STATUS;
}
private void addBootstrapJar(Set<URL> urls, File rooHome, String directory) {
File dir = new File(rooHome.getAbsolutePath(), directory);
if (dir.exists()) {
for (File jar : dir.listFiles()) {
if (jar.isFile() && jar.getName().endsWith(".jar") && !jar.getName().contains("jline")) {
try {
urls.add(jar.toURI().toURL());
}
catch (MalformedURLException e) {
}
}
}
}
}
private String versionInfo() {
ClassLoader loader = new URLClassLoader(getClasspath());
// Try to determine the bundle version
String bundleVersion = null;
String gitCommitHash = null;
JarFile jarFile = null;
try {
URL classContainer = loader.loadClass("org.springframework.roo.shell.AbstractShell").getProtectionDomain()
.getCodeSource().getLocation();
if (classContainer.toString().endsWith(".jar")) {
// Attempt to obtain the "Bundle-Version" version from the
// manifest
jarFile = new JarFile(new File(classContainer.toURI()), false);
ZipEntry manifestEntry = jarFile.getEntry("META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(jarFile.getInputStream(manifestEntry));
bundleVersion = manifest.getMainAttributes().getValue("Bundle-Version");
gitCommitHash = manifest.getMainAttributes().getValue("Git-Commit-Hash");
}
}
catch (Exception ignoreAndMoveOn) {
}
finally {
if (jarFile != null) {
try {
jarFile.close();
}
catch (IOException e) {
}
}
}
StringBuilder sb = new StringBuilder();
if (bundleVersion != null) {
sb.append(bundleVersion);
}
if (gitCommitHash != null) {
if (sb.length() > 0) {
sb.append(" "); // to separate from version
}
sb.append("[rev ");
sb.append(gitCommitHash.substring(0, 7));
sb.append("]");
}
if (sb.length() == 0) {
sb.append(UNKNOWN_VERSION);
}
return sb.toString();
}
}