/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, 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 Software, Inc. - initial API and implementation
*******************************************************************************/
package org.grails.ide.eclipse.core.model;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.grails.ide.eclipse.core.GrailsCoreActivator;
import org.grails.ide.eclipse.core.internal.model.DefaultGrailsInstall;
import org.springsource.ide.eclipse.commons.core.SpringCorePreferences;
import org.springsource.ide.eclipse.commons.core.SpringCoreUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* @author Christian Dupuis
* @author Kris De Volder
*/
public class GrailsInstallManager {
private Map<String, IGrailsInstall> installs = new ConcurrentHashMap<String, IGrailsInstall>();
private List<IGrailsInstallListener> listeners = new ArrayList<IGrailsInstallListener>();
public IGrailsInstall getGrailsInstall(IProject project) {
if (project == null) {
return getDefaultGrailsInstall();
}
GrailsVersion version = GrailsVersion.getGrailsVersion(project);
return getInstallFor(version);
}
public IGrailsInstall getGrailsInstall(String name) {
return installs.get(name);
}
public IGrailsInstall getDefaultGrailsInstall() {
for (IGrailsInstall install : installs.values()) {
if (install.isDefault()) {
return install;
}
}
if (installs.size() > 0) {
return installs.values().iterator().next();
}
return null;
}
public void start() {
try {
boolean readFromLegacyLocation = false;
DocumentBuilder docBuilder = SpringCoreUtils.getDocumentBuilder();
IPath grailsInstallFile = GrailsCoreActivator.getDefault().getStateLocation().append("grails.installs");
if (!grailsInstallFile.toFile().exists()) {
//Try legacy state location.
//path looks like this: <workspace>/.metadata/.plugins/org.grails.ide.eclipse.core/grails.installs
//legacypath like this: <workspace>/.metadata/.plugins/OLD_PLUGIN_ID/grails.installs
grailsInstallFile = grailsInstallFile.removeLastSegments(2).append(GrailsCoreActivator.OLD_PLUGIN_ID+"/grails.installs");
readFromLegacyLocation = true;
}
if (grailsInstallFile.toFile().exists()) {
Document doc = docBuilder.parse(grailsInstallFile.toFile());
NodeList installNodes = doc.getElementsByTagName("install");
for (int i = 0; i < installNodes.getLength(); i++) {
Node installNode = installNodes.item(i);
String name = null;
String home = null;
boolean isDefault = false;
NodeList installChildren = installNode.getChildNodes();
for (int j = 0; j < installChildren.getLength(); j++) {
Node installChild = installChildren.item(j);
if ("name".equals(installChild.getNodeName())) {
name = installChild.getTextContent();
}
else if ("home".equals(installChild.getNodeName())) {
home = installChild.getTextContent();
}
}
Node defaultNode = installNode.getAttributes().getNamedItem("is-default");
if (defaultNode != null && defaultNode.getNodeValue().equalsIgnoreCase("true")) {
isDefault = true;
}
if (name != null && home != null) {
DefaultGrailsInstall install = new DefaultGrailsInstall(home, name, isDefault);
installs.put(name, install);
}
else {
GrailsCoreActivator.log("Discarding Grails install [" + home + "] with name [" + name + "]",
null);
}
if (readFromLegacyLocation) {
//Make a copy in the new location (consistent with how other preferences files are migrated)
save(doc);
}
}
}
}
catch (SAXException e) {
GrailsCoreActivator.log(e);
}
catch (IOException e) {
GrailsCoreActivator.log(e);
}
}
public void setGrailsInstalls(Set<IGrailsInstall> newInstalls) {
IGrailsInstall oldDefault = getDefaultGrailsInstall();
installs.clear();
DocumentBuilder documentBuilder = SpringCoreUtils.getDocumentBuilder();
Document document = documentBuilder.newDocument();
Element root = document.createElement("installs");
document.appendChild(root);
for (IGrailsInstall install : newInstalls) {
installs.put(install.getName(), install);
Element installNode = document.createElement("install");
root.appendChild(installNode);
// add is-default attribute
Attr isDefaultAttribute = document.createAttribute("is-default");
installNode.setAttributeNode(isDefaultAttribute);
isDefaultAttribute.setValue(Boolean.toString(install.isDefault()));
// add home element
Element homeNode = document.createElement("home");
installNode.appendChild(homeNode);
homeNode.appendChild(document.createTextNode(install.getHome()));
Element nameNode = document.createElement("name");
installNode.appendChild(nameNode);
nameNode.appendChild(document.createTextNode(install.getName()));
}
save(document);
IGrailsInstall newDefault = getDefaultGrailsInstall();
for (IGrailsInstallListener listener : listeners) {
listener.installsChanged(newInstalls);
if (!equals(oldDefault, newDefault)) {
listener.defaultInstallChanged(oldDefault, newDefault);
}
}
}
/**
* Equals comparison that is null pointer safe.
*/
private boolean equals(Object x, Object y) {
if (x==null) {
return y==null;
} else {
return x.equals(y);
}
}
private void save(Document document) {
try {
IPath grailsInstallFile = GrailsCoreActivator.getDefault().getStateLocation().append("grails.installs");
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
Writer out = new OutputStreamWriter(new FileOutputStream(grailsInstallFile.toFile()), "ISO-8859-1");
StreamResult result = new StreamResult(out);
DOMSource source = new DOMSource(document);
transformer.transform(source, result);
out.close();
} catch (IOException e) {
GrailsCoreActivator.log(e);
}
catch (TransformerException e) {
GrailsCoreActivator.log(e);
}
}
public void addGrailsInstallListener(IGrailsInstallListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
public void removeGrailsInstallListener(IGrailsInstallListener listener) {
listeners.remove(listener);
}
public Collection<IGrailsInstall> getAllInstalls() {
Set<IGrailsInstall> newInstalls = new HashSet<IGrailsInstall>();
for (IGrailsInstall install : installs.values()) {
newInstalls.add(new DefaultGrailsInstall(install.getHome(), install.getName(), install.isDefault()));
}
return newInstalls;
}
public String[] getAllInstallNames() {
Set<String> newInstalls = new HashSet<String>();
for (IGrailsInstall install : installs.values()) {
newInstalls.add(install.getName());
}
return newInstalls.toArray(new String[newInstalls.size()]);
}
/**
* @return A grails install of the specified version, or null if no such install is configured in the
* workspace.
*/
public IGrailsInstall getInstallFor(GrailsVersion grailsVersion) {
Collection<IGrailsInstall> candidates = getAllInstalls();
for (IGrailsInstall install : candidates) {
if (grailsVersion.equals(install.getVersion())) {
return install;
}
}
return null;
}
}