/*******************************************************************************
* Copyright (c) 2012 - 2015 Spring IDE Developers
* 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:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package com.vmware.vfabric.ide.eclipse.tcserver.internal.core;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.eclipse.wst.server.core.IServerAttributes;
import org.springsource.ide.eclipse.commons.core.FileUtil;
/**
* @author Tomasz Zarna
*
*/
public class TemplatePropertiesReader {
private static final String CONFIGURATION_PROMPTS_PROPERTIES = "configuration-prompts.properties";
private static final String SERVER_FRAGMENT_XML = "conf/server-fragment.xml";
private static final String CONTEXT_FRAGMENT_XML = "conf/context-fragment.xml";
private static final String SSL_PROPERTIES = "conf/ssl.properties";
private final IServerAttributes serverAttributes;
@SuppressWarnings("serial")
static private class OrderedProperties extends Properties {
private final Vector<String> names;
public OrderedProperties() {
super();
names = new Vector<String>();
}
public Enumeration<String> propertyNames() {
return names.elements();
}
public Object put(Object key, Object value) {
if (names.contains(key)) {
names.remove(key);
}
names.add((String) key);
return super.put(key, value);
}
public Object remove(Object key) {
names.remove(key);
return super.remove(key);
}
}
public TemplatePropertiesReader(IServerAttributes serverAttributes) {
this.serverAttributes = serverAttributes;
}
public Set<TemplateProperty> read(String templateName, IProgressMonitor monitor) throws CoreException {
TcServerRuntime tcRuntime = (TcServerRuntime) serverAttributes.getRuntime().loadAdapter(TcServerRuntime.class,
monitor);
if (tcRuntime != null) {
File templateDir = tcRuntime.getTemplateFolder(templateName);
if (templateDir.exists()) {
return read(templateDir, monitor);
}
}
return null;
}
private Set<TemplateProperty> read(File templateDir, IProgressMonitor monitor) throws CoreException {
File configurationPromptsFile = new File(templateDir, CONFIGURATION_PROMPTS_PROPERTIES);
Properties props = new TemplatePropertiesReader.OrderedProperties();
if (!configurationPromptsFile.exists()) {
return Collections.emptySet();
}
try {
FileReader in = new FileReader(configurationPromptsFile);
props.load(in);
}
catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR, TcServerCorePlugin.PLUGIN_ID, "Could not read file \""
+ configurationPromptsFile + "\"", e));
}
if (props.size() == 0) {
return Collections.emptySet();
}
File fragmentXmlFile = new File(templateDir, SERVER_FRAGMENT_XML);
if (!fragmentXmlFile.exists() || !fragmentXmlFile.isFile()) {
fragmentXmlFile = new File(templateDir, CONTEXT_FRAGMENT_XML);
}
String serverFragmentContent = FileUtil.readFile(fragmentXmlFile, monitor);
File sslPropertiesFile = new File(templateDir, SSL_PROPERTIES);
String sslPropertiesContent = null;
if (sslPropertiesFile.exists()) {
sslPropertiesContent = FileUtil.readFile(sslPropertiesFile, monitor);
}
Set<TemplateProperty> result = new LinkedHashSet<TemplateProperty>(props.size());
Enumeration e = props.propertyNames();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
String defaultValue = null;
if ("runtime.user".equals(key)) {
// special case for a property from "base" template
File initdShFile = new File(templateDir, "bin/init.d.sh");
if (initdShFile.exists()) {
String initdShContent = FileUtil.readFile(initdShFile, monitor);
defaultValue = findDefaultValue(key, initdShContent);
}
}
else {
defaultValue = findDefaultValue(key, serverFragmentContent);
if (defaultValue == null && sslPropertiesContent != null) {
defaultValue = findDefaultValue(key, sslPropertiesContent);
}
if (defaultValue != null) {
if (isLinked(defaultValue)) {
defaultValue = resolveLink(result, defaultValue);
}
else if (!isResolved(defaultValue)) {
defaultValue = resolve(defaultValue);
}
}
}
result.add(new TemplateProperty(templateDir.getName(), key, props.getProperty(key), defaultValue));
}
// TODO: cyclomatic complexity went through the roof
// refactor when another "special case" is found
return result;
}
private static boolean isLinked(String defaultValue) {
return findLink(defaultValue) != null;
}
private static String findLink(String defaultValue) {
Pattern pattern = Pattern.compile("\\$\\{([^:]+)\\}");
Matcher matcher = pattern.matcher(defaultValue);
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
private static String resolveLink(Set<TemplateProperty> propsFoundSoFar, String defaultValue) {
String key = findLink(defaultValue);
for (TemplateProperty prop : propsFoundSoFar) {
if (prop.getKey().equals(key)) {
return prop.getRawDefault();
}
}
return defaultValue;
}
private static boolean isResolved(String defaultValue) {
return findDefaultValue(".*", defaultValue) == null;
}
private static String resolve(String defaultValue) {
String embeded = findDefaultValue(".*", defaultValue);
return defaultValue.replaceFirst("\\$\\{.*:" + embeded + "\\}", embeded);
}
private static String findDefaultValue(String key, String serverFragmentContent) {
Pattern pattern = Pattern.compile("\\$\\{" + key + ":([^=]+)\\}");
Matcher matcher = pattern.matcher(serverFragmentContent);
if (matcher.find()) {
return matcher.group(1);
}
return null;
}
}