/*******************************************************************************
* Copyright (c) 2013 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.wizard.template.infrastructure;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.springframework.ide.eclipse.wizard.WizardPlugin;
import org.springframework.ide.eclipse.wizard.template.SimpleProject;
import org.springsource.ide.eclipse.commons.content.core.ContentItem;
import org.springsource.ide.eclipse.commons.content.core.ContentLocation;
import org.springsource.ide.eclipse.commons.content.core.ContentManager;
import org.springsource.ide.eclipse.commons.content.core.ContentPlugin;
import org.springsource.ide.eclipse.commons.content.core.util.Descriptor;
import org.springsource.ide.eclipse.commons.content.core.util.DescriptorReader;
import org.springsource.ide.eclipse.commons.content.core.util.IContentConstants;
import org.springsource.ide.eclipse.commons.internal.content.core.DescriptorMatcher;
/**
* Manages the content of Simple Projects that are bundled in the Wizard Plugin.
* Addition content locations for Simple Projects can also be added to the
* manager. The manager unzips the simple project files in a local installation
* directory, and also read the files and adds them into a simple project data
* model.
*
*/
public class SimpleProjectContentManager {
private final List<ContentLocation> contentLocations = new ArrayList<ContentLocation>();
private List<ContentItem> projectItems = null;
private static SimpleProjectContentManager manager;
public static final String INSTALL_DIRECTORY = "simpleprojects";
public static SimpleProjectContentManager getManager() {
if (manager == null) {
manager = new SimpleProjectContentManager();
ContentLocation location = WizardPlugin.getDefault().getTemplateContentLocation();
manager.addContentLocation(location);
}
return manager;
}
/**
* Adds a non-null content location, if not already present. Initialises the
* content manager afterward.
* @param contentLocation
*/
public void addContentLocation(ContentLocation contentLocation) {
if (contentLocation != null && !contentLocations.contains(contentLocation)) {
contentLocations.add(contentLocation);
}
}
/**
* Directory where simple project zip files are unzipped. Usually it is
* located in the workspace .metadata/.sts directory. If the installation
* directory does not exist, it will create it, as well as its parents if
* necessary.
* @return installation directory.
*/
public File getInstallDirectory() {
ContentManager manager = ContentPlugin.getDefault().getManager();
// Install Simple projects in a separate directory so that they do not
// get managed by the content manager
// for templates, since simple projects get treated differently.
// However, the parent of the content manager
// install directory should be the same (i.e. [workspace]/.metadata/.sts
File file = new File(manager.getDataDirectory(), INSTALL_DIRECTORY);
if (!file.exists()) {
file.mkdirs();
}
return file;
}
/**
* Creates content items for each simple project descriptor listed in a
* descriptor.xml file. The descriptor.xml file is indicated via a content
* location that can be set in the content manager. A content item is a
* lightweight representation of a descriptor that does not actually point
* to the simple project zip file, but rather contains metadata of the
* simple project. The list of content items is only read once per runtime
* session, as content items locations are not meant to be dynamically
* changed, unlike project templates. Simple project files are not handled
* or unzipped during this process.
* @return
* @throws CoreException if error occurred when reading descriptors from a
* content location.
*/
public List<ContentItem> readFromContentLocations() throws CoreException {
if (projectItems != null && !projectItems.isEmpty()) {
return projectItems;
}
projectItems = new ArrayList<ContentItem>();
for (ContentLocation location : contentLocations) {
File file = location.getContentLocationFile();
if (file != null && file.exists()) {
projectItems.addAll(read(file));
}
}
return projectItems;
}
protected List<ContentItem> read(File file) throws CoreException {
DescriptorMatcher matcher = new DescriptorMatcher(getInstallDirectory());
DescriptorReader reader = new DescriptorReader();
reader.read(file);
List<Descriptor> descriptors = reader.getDescriptors();
List<ContentItem> items = new ArrayList<ContentItem>();
for (Descriptor descriptor : descriptors) {
// Verify if the descriptor ID and version match an expected pattern
// for the descriptor's
// files. See the matcher for the actual matching criteria.
if (!matcher.match(descriptor)) {
continue;
}
ContentItem item = new ContentItem(descriptor.getId());
item.setLocalDescriptor(descriptor);
items.add(item);
}
return items;
}
/**
* Resolves a list of Simple Projects, each with loaded project data. This
* iterates through simple project descriptors, if necessary unzipping
* project data files, if they weren't already unzipped in a previous run in
* the installation directory for simple projects. I also loads simple
* project files into a data object that it sets in each simple project.
* Throws exception if errors occur in any of these stages.
* @param monitor
* @return List of simple projects resolved from simple project descriptors
* in a content location.
* @throws CoreException
*/
public List<SimpleProject> getSimpleProjects(IProgressMonitor monitor) throws CoreException {
File baseDir = getInstallDirectory();
if (baseDir == null || !baseDir.exists()) {
throw new CoreException(
new Status(
IStatus.ERROR,
WizardPlugin.PLUGIN_ID,
"Unable to unzip Spring simple project zip files, possibly due to write permission error when creating simple project content directory in: "
+ ContentPlugin.getDefault().getManager().getDataDirectory().toString()));
}
List<ContentItem> projectItems = readFromContentLocations();
List<SimpleProject> projects = new ArrayList<SimpleProject>();
for (ContentItem item : projectItems) {
if (SimpleProjectFactory.isSimpleProject(item)) {
SimpleProject simpleProject = SimpleProjectFactory.getSimpleProject(item);
if (simpleProject != null) {
BundleContentLoader loader = new BundleContentLoader(item, WizardPlugin.getDefault().getBundle(),
this);
loader.load(monitor);
// Now get the project install directory so that the project
// data can be read from it
File projectDir = new File(baseDir, item.getPath());
TemplateProjectData data = new TemplateProjectData(projectDir);
data.read();
// Important that the data be set, otherwise the simple
// project cannot be processed
simpleProject.setTemplateData(data);
projects.add(simpleProject);
}
}
}
return projects;
}
public boolean exists(File projectToLookFor) {
File dir = getInstallDirectory();
File[] children = dir.listFiles();
if (children == null || children.length <= 0) {
return false;
}
for (File childDirectory : children) {
if (childDirectory.isDirectory() && childDirectory.getName().equals(projectToLookFor.getName())) {
// If the installation directory for the simple project contains
// one of the project files, and matches the versioned name of
// the project to look for, assume it exists
if ((new File(childDirectory, IContentConstants.TEMPLATE_DATA_FILE_NAME).exists())) {
return true;
}
}
}
return false;
}
}