/*
* NOTE: This copyright does *not* cover user programs that use HQ
* program services by normal system calls through the application
* program interfaces provided as part of the Hyperic Plug-in Development
* Kit or the Hyperic Client Development Kit - this is merely considered
* normal use of the program, and does *not* fall under the heading of
* "derived work".
*
* Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
* This file is part of HQ.
*
* HQ is free software; you can redistribute it and/or modify
* it under the terms version 2 of the GNU General Public License as
* published by the Free Software Foundation. This program is distributed
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package org.hyperic.tools.ant;
import java.io.EOFException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.security.KeyStoreException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.util.Getline;
import org.hyperic.tools.ant.installer.InstallerConfigSchemaProvider;
import org.hyperic.util.config.AutomatedResponseBuilder;
import org.hyperic.util.config.ConfigResponse;
import org.hyperic.util.config.ConfigSchema;
import org.hyperic.util.config.EarlyExitException;
import org.hyperic.util.config.InteractiveResponseBuilder;
import org.hyperic.util.config.InteractiveResponseBuilder_IOHandler;
import org.hyperic.util.config.ReturnStepsException;
import org.hyperic.util.config.SkipConfigException;
import org.hyperic.util.security.KeystoreConfig;
import org.hyperic.util.security.KeystoreManager;
public class ConfigSchemaTask
extends Task
implements InteractiveResponseBuilder_IOHandler {
private String itsClass;
private String itsInputPrefix;
private String itsOutputPrefix;
private String itsInstallDirPropName;
private File itsFile;
private File itsLoadFile;
private File itsCompletionFile;
private String itsIfDefined;
private boolean itsReplaceInstallDir = false;
private Project itsProject;
private InstallerConfigSchemaProvider itsSchemaProvider;
private ConfigResponse itsResponse;
private final Getline gl;
private List<EncryptProperty> encryptProperties = new ArrayList<EncryptProperty>();
public ConfigSchemaTask () {
try {
Sigar.load();
} catch (SigarException e) {
e.printStackTrace(); //should never happen
}
this.gl = new Getline();
}
public void setClass ( String c ) {
itsClass = c;
}
public void setInputPrefix ( String p ) {
itsInputPrefix = p;
}
public void setOutputPrefix ( String p ) {
itsOutputPrefix = p;
}
public void setFile ( File f ) {
itsFile = f;
}
public void setLoadFile ( File f ) {
itsLoadFile = f;
}
public void setInstallDirPropName ( String p ) {
itsInstallDirPropName = p;
}
public void setCompletionFile ( File f ) {
itsCompletionFile = f;
}
public void setIfDefined ( String prop ) {
itsIfDefined = prop;
}
public void setReplaceInstallDir( boolean b ) {
itsReplaceInstallDir = b;
}
public void addEncryptProperty(EncryptProperty encryptProperty){
encryptProperties.add(encryptProperty);
}
@Override
public void execute () throws BuildException {
validateAttributes();
itsProject = getProject();
boolean isInteractive = (itsLoadFile == null);
itsSchemaProvider.setProjectProperties(itsProject.getProperties());
String installDir = itsProject.getProperty(itsInstallDirPropName);
itsSchemaProvider.setInstallDir(installDir);
ConfigSchema schema;
InteractiveResponseBuilder sb;
try {
sb = isInteractive
? new InteractiveResponseBuilder(this)
: new AutomatedResponseBuilder(this,
this.itsLoadFile,
this.itsIfDefined);
} catch (Exception exc) {
throw new BuildException("Error loading properties from file: " + this.itsLoadFile.getPath(), exc);
}
ConfigResponse response = null;
ConfigResponse mergedResponse = null;
int i=0;
try {
schema = itsSchemaProvider.getSchema(response, i);
} catch (SkipConfigException e) {
return;
} catch (EarlyExitException e) {
throw new BuildException(e);
}
int failureCount = 0;
while ( schema != null ) {
try {
response = sb.processConfigSchema(schema);
} catch (SkipConfigException e) {
return;
} catch ( EarlyExitException e ) {
throw new BuildException(e);
} catch ( Exception e ) {
throw new BuildException("Error getting configuration: "
+ e, e);
}
if ( mergedResponse == null ) mergedResponse = response;
else mergedResponse.merge(response, true);
i++;
try {
schema = itsSchemaProvider.getSchema(mergedResponse, i);
}
catch (EarlyExitException e) {
throw new BuildException(e);
}
catch (ReturnStepsException e) {
if (failureCount++ >= 2) {
throw new BuildException("Cannot continue with the installation after 3 unsuccessful attempts.");
}
errOutput("---------------------------------------------------------------------------------");
errOutput(e.getMessage());
errOutput("---------------------------------------------------------------------------------");
i = e.getStepToReturnTo();
schema = itsSchemaProvider.getSchema(mergedResponse, i);
}
}
// ...generate or load our internal keystore...
// ...store in data dir temporarily and copy it to correct location in ant script...
String path = itsFile.getParent();
String filePath = path + "/hyperic.keystore";
String filePassword = "hyperic";
KeystoreConfig config = new KeystoreConfig("hq", filePath, filePassword, true);
try {
KeystoreManager.getKeystoreManager().getKeyStore(config);
} catch (KeyStoreException e) {
throw new BuildException(e);
} catch (IOException e) {
throw new BuildException(e);
}
if (itsReplaceInstallDir) {
String newInstallDir
= mergedResponse.getValue(itsSchemaProvider.getBaseName()
+ ".installdir");
itsProject.setProperty(itsInstallDirPropName,
newInstallDir);
}
// Generate summary text
String completionText
= itsSchemaProvider.getCompletionText(mergedResponse);
if (completionText == null) completionText = "";
// write to files
Iterator iter = mergedResponse.getKeys().iterator();
String key, value;
Properties props = new Properties();
while ( iter.hasNext() ) {
key = (String) iter.next();
value = mergedResponse.getValue(key);
for (EncryptProperty encryptProperty:encryptProperties){
if(key.equals(encryptProperty.getProperty())){
props.setProperty(key, "******");
key = encryptProperty.getTargetProperty();
value = encryptProperty.encode(value);
break;
}
}
props.setProperty(key, value);
}
FileOutputStream fos = null;
FileWriter fw = null;
try {
if (itsFile != null) {
fos = new FileOutputStream(itsFile.getAbsolutePath(), true);
props.store(fos, "Autogenerated Configuration");
}
if (itsCompletionFile != null) {
fw = new FileWriter(itsCompletionFile);
fw.write(completionText);
}
} catch ( Exception e ) {
throw new BuildException("Error writing to properties file: "
+ e, e);
} finally {
if (fos != null) try { fos.close(); } catch (IOException e) {}
if (fw != null) try { fw.close(); } catch (IOException e) {}
}
}
public void validateAttributes () throws BuildException {
if ( itsClass == null ) {
throw new BuildException("ConfigSchema: No 'class' "
+ "attribute specified.");
}
try {
Object o = Class.forName(itsClass).newInstance();
itsSchemaProvider = (InstallerConfigSchemaProvider) o;
} catch ( Exception e ) {
throw new BuildException("ConfigSchema: error instantiating "
+ "schema provder class: "
+ itsClass + ":" + e, e);
}
if ( itsOutputPrefix == null ) itsOutputPrefix = "";
if ( itsInputPrefix == null ) itsInputPrefix = "";
if ( itsFile == null && itsLoadFile == null ) {
throw new BuildException("ConfigSchema: No 'file' or 'loadFile' "
+ "attribute specified.");
}
if (itsLoadFile == null && itsIfDefined != null) {
throw new BuildException("ConfigSchema: Cannot specify 'ifDefined' "
+ "attribute without 'loadFile' "
+ "attribute.");
}
}
/** @see org.hyperic.util.config.InteractiveResponseBuilder.IOHandler#handleInput */
public String handleInput ( String prompt ) throws EOFException, IOException {
itsProject.log(itsInputPrefix + prompt);
return this.gl.getLine("");
}
public String handleHiddenInput ( String prompt )
throws EOFException, IOException
{
// itsProject.log(itsInputPrefix + prompt);
return Sigar.getPassword(prompt);
}
/** @see org.hyperic.util.config.InteractiveResponseBuilder.IOHandler#errOutput */
public void errOutput ( String msg ) {
itsProject.log(itsOutputPrefix + msg);
}
/** @see org.hyperic.util.config.InteractiveResponseBuilder.IOHandler#isDeveloper */
public boolean isDeveloper () {
return false;
}
}