/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the License).  You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * Header Notice in each file and include the License file 
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.  
 * If applicable, add the following below the CDDL Header, 
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information: 
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */

package com.sun.enterprise.admin.servermgmt;

import com.sun.enterprise.util.i18n.StringManager;
import com.sun.enterprise.admin.util.LineTokenReplacer;
import com.sun.enterprise.admin.util.TokenValue;
import com.sun.enterprise.admin.util.TokenValueSet;
import com.sun.enterprise.util.OS;
import com.sun.enterprise.util.ProcessExecutor;
import java.io.File;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


/** An implementation of {@link ServiceHandler} interface for the Solaris 10 SMF.
 * The service is created as a standard S10 service. The class tries to validate
 * and import the service in a disabled state. The users are expected to enable
 * the service later.
 * Here is a typical way for clients to use this class ensuring that they are on S10 and SMF is enabled:
 * <pre>
 * final ServiceHandler sh  = new SMFServiceHandler();
 * final SMFService service = new SMFService();
 * //configure service
 * service.setDate(new Date().toString());
 * service.setName("salesdomain");
 * service.setLocation("/homes/sales/domains");
 * service.setType(AppserverServiceType.Domain);
 * service.setOSUser("joe");
 * //...
 * <b><u>service.isConfigValid();</b></u> //this is important
 * sh.createService(service.tokensAndValues());
 * </pre>
 * @since SJSAS 9.0
 * @see SMFService
 */
public class SMFServiceHandler implements ServiceHandler {
    
    private static final StringManager sm = StringManager.getManager(SMFServiceHandler.class);
    private boolean trace = false;
    /** The default constructor.
     */
    public SMFServiceHandler() {
    }

    public void createService(final Map<String, String> params) throws RuntimeException {
        final SMFService smf = new SMFService(params);
        boolean success = false;
        try {
            smf.isConfigValid(); //safe, throws exception if not valid
            if (trace)
                printOut(smf.toString());
            testPlatform();
            validateManifest(smf.getManifestFilePath());
            tokenReplaceTemplateAtDestination(smf);
            validateService(smf);
            success = importService(smf);
        } catch(final Exception e) {
            if (!success) {
                cleanupManifest(smf);
            }
            throw new RuntimeException(e);
        }
    }

    private void testPlatform() throws Exception {
        if (!OS.isSolaris10()) {
            final String os  = System.getProperty("os.name");
            final String vr  = System.getProperty("os.version");
            final String msg = sm.getString("notSolaris10", os, vr);
            throw new IllegalArgumentException(msg);
        }
    }
    private void validateManifest(final String manifestPath) throws Exception {
        final File manifest = new File(manifestPath);
        if (manifest.exists()) {
            final String msg = sm.getString("smfManifestExists", manifest.getAbsolutePath());
            throw new IllegalArgumentException(msg);
        }
        if (manifest.getParentFile().exists()) {
            final String msg = sm.getString("smfManifestFolderExists", manifest.getParentFile().getAbsolutePath());
            throw new IllegalArgumentException(msg);
        }
        manifest.getParentFile().mkdirs();
        if (trace)
            printOut("Manifest validated: " + manifestPath);
    }
    private void tokenReplaceTemplateAtDestination(final SMFService smf) throws Exception {
        final LineTokenReplacer tr = new LineTokenReplacer(map2Set(smf.tokensAndValues()));
        tr.replace(smf.getManifestFileTemplatePath(), smf.getManifestFilePath());
        if (trace)
            printOut("Manifest configured: " + smf.getManifestFilePath());
    }
    
    private TokenValueSet map2Set(final Map<String, String> map) throws Exception {
        final Set<TokenValue> set = new HashSet<TokenValue> ();
        final Set<String> keys = map.keySet();
        for (final String key : keys) {
            final String value      = map.get(key);
            final TokenValue tv     = new TokenValue(key, value);
            set.add(tv);
        }
        final TokenValueSet tvset = new TokenValueSet(set);
        return ( tvset );
    }
    
    private void validateService(final SMFService smf) throws Exception {
        final String[] cmda = new String[]{SMFService.SVCCFG, "validate", smf.getManifestFilePath()};
        final ProcessExecutor pe = new ProcessExecutor(cmda);
        pe.execute();
        if (trace)
            printOut("Validated the SMF Service: " + smf.getFQSN() + " using: " + SMFService.SVCCFG);
    }
    private boolean importService(final SMFService smf) throws Exception {
        final String[] cmda = new String[]{SMFService.SVCCFG, "import", smf.getManifestFilePath()};
        final ProcessExecutor pe = new ProcessExecutor(cmda);
        pe.execute(); //throws ExecException in case of an error
        if (trace)
            printOut("Imported the SMF Service: " + smf.getFQSN());
        return ( true );
    }
    private void cleanupManifest(final SMFService smf) throws RuntimeException {
        final File manifest = new File(smf.getManifestFilePath());
        if (manifest.exists()) {
            manifest.delete();
            manifest.deleteOnExit();
            if(trace)
                printOut("Attempted deleting failed service manifest: " + manifest.getAbsolutePath());
        }
        final File failedServiceNode = manifest.getParentFile();
        if (failedServiceNode.exists()) {
            failedServiceNode.delete();
            failedServiceNode.deleteOnExit();
            if(trace)
                printOut("Attempted deleting failed service folder: " + failedServiceNode.getAbsolutePath());
        }
    }
    private void printOut(final String s) {
        System.out.println(s);
    }

    public void setTrace(boolean trace) {
        this.trace = trace;
    }
}
