FileDocCategorySizeDatePackage
SMFService.javaAPI DocGlassfish v2 API29347Thu May 17 17:51:54 BST 2007com.sun.enterprise.admin.servermgmt

SMFService

public final class SMFService extends Object implements Service
Represents the SMF Service. Holds the tokens and their values that are consumed by the SMF templates. The recommended way to use this class (or its instances) is to initialize it with default constructor and then apply various mutators to configure the service. Finally, callers should make sure that the configuration is valid, before attempting to create the service in the Solaris platform.
since
SJSAS 9.0
see
#isConfigValid
see
SMFServiceHandler

Fields Summary
public static final String
DATE_CREATED_TN
public static final String
SERVICE_NAME_TN
public static final String
SERVICE_TYPE_TN
public static final String
CFG_LOCATION_TN
public static final String
ENTITY_NAME_TN
public static final String
FQSN_TN
public static final String
AS_ADMIN_PATH_TN
public static final String
AS_ADMIN_USER_TN
public static final String
AS_ADMIN_PASSWORD_TN
public static final String
AS_ADMIN_MASTERPASSWORD_TN
public static final String
PASSWORD_FILE_PATH_TN
public static final String
TIMEOUT_SECONDS_TN
public static final String
OS_USER_TN
public static final String
PRIVILEGES_TN
public static final String
TIMEOUT_SECONDS_DV
public static final String
AS_ADMIN_USER_DEF_VAL
public static final String
SVCCFG
public static final String
SVCADM
public static final String
SP_DELIMITER
public static final String
PRIVILEGES_DEFAULT_VAL
public static final String
NETADDR_PRIV_VAL
public static final String
BASIC_NETADDR_PRIV_VAL
public static final String
START_INSTANCES_TN
public static final String
START_INSTANCES_DEFAULT_VAL
public static final String
NO_START_INSTANCES_PROPERTY
public static final String
MANIFEST_HOME
private static final String
NULL_VALUE
private static final String
SERVICE_NAME_PREFIX
private static final com.sun.enterprise.util.i18n.StringManager
sm
private static final String
nullArgMsg
private static final String
MANIFEST_FILE_SUFFIX
private static final String
MANIFEST_FILE_TEMPL_SUFFIX
private final Map
pairs
private boolean
trace
Constructors Summary
public SMFService()
Creates SMFService instance. All the tokens are initialized to default values. Callers must verify that the tokens are properly token-replaced before using this instance.

    
                                  
      
        final boolean smfExists = new File(SVCADM).exists();
        // The above was suggsted by smf-discuss forum on OpenSolaris
        if (OS.isSun() && !smfExists) {
            throw new IllegalArgumentException("");
        }
        pairs = new HashMap<String, String> ();
        init();
    
public SMFService(Map tv)
Creates SMFService instance with tokens initialized from given map. Given Map may not be null. Callers must verify that the tokens are properly token-replaced before using this instance.

param
tv a Map of that contains mappings between tokens and their values
throws
IllegalArgumentException in case the parameter is null

        if (tv == null)
            throw new IllegalArgumentException(nullArgMsg);
        pairs = new HashMap<String, String> (tv);
    
Methods Summary
private static voidIGNORE_EXCEPTION(java.lang.Exception e)

        // ignore
    
private booleancanCreateManifest()

        final File mh = new File(MANIFEST_HOME);
        boolean ok = true;
        if (!mh.exists()) {
            ok = mh.mkdirs();
        }
        if (ok) {
            if (!mh.canWrite()) {
                ok = false;
            }
        }
        return ( ok );
    
private voidcleanupManifest(com.sun.enterprise.admin.servermgmt.SMFService smf)

        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());
        }
    
public voidcreateService(java.util.Map params)
Creates the service on the given platform.

        final SMFService smf = new SMFService(params);
        boolean success = false;
        boolean previousManifestExists = new File(smf.getManifestFilePath()).exists();
        try {
            smf.isConfigValid(); //safe, throws exception if not valid
            if (trace)
                printOut(smf.toString());
            validateManifest(smf.getManifestFilePath());
            previousManifestExists = false;
            tokenReplaceTemplateAtDestination(smf);
            validateService(smf);
            success = importService(smf);
        } catch(final Exception e) {
            if (!success && !previousManifestExists) {
                cleanupManifest(smf);
            }
            throw new RuntimeException(e);
        }
    
private booleanfileContainsToken(java.lang.String path, java.lang.String t, java.util.Map tv)

        BufferedInputStream bis = null;
        try {
            boolean present = false;
            bis = new BufferedInputStream(new FileInputStream(path));
            final Properties p = new Properties();
            p.load(bis);
            if (p.containsKey(t)) {
                tv.put(t, (String)p.get(t));
                present = true;
            }
            return ( present );
        }
        catch(final Exception e) {
            throw new RuntimeException(e);
        }
        finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch(Exception ee) {
                    IGNORE_EXCEPTION(ee);
                }
            }
        }
    
public java.lang.StringgetAsadminPath()
Returns the absolute path to the asadmin script.

        return (pairs.get(AS_ADMIN_PATH_TN) );
    
public java.lang.StringgetDate()
Returns the date the service is created.

return
A String Representation of Date.
see
java.util.Date

        return ( pairs.get(DATE_CREATED_TN) );
    
public java.lang.StringgetFQSN()
Returns the so-called Fully Qualified Service Name for this service. It is a function of name and location where the configuration of the service is stored. Might not return the intended value if the name and/or location is not set prior to this call.

return
String representing the place where the manifest is stored

        return ( pairs.get(FQSN_TN) );
    
public java.lang.StringgetLocation()
Returns the location where configuration of the service is stored on the disk.

        return ( pairs.get(CFG_LOCATION_TN) );
    
public java.lang.StringgetManifestFilePath()
Returns the absolute location of the manifest file as SMF understands it. It takes into account the name, type and configuration location of the service. It is expected that these are set before calling this method. If the Fully Qualified Service Name is invalid, a RuntimeException results.

        final String fqsn           = getFQSN();
        if (NULL_VALUE.equals(fqsn)) {
            final String msg = sm.getString("serviceNameInvalid", fqsn);
            throw new RuntimeException(msg);
        }
        //now we are sure that this is called after proper configuration
        final String fn = new StringBuilder().append(MANIFEST_HOME).append(fqsn).append("/").append(this.getType().toString()).append(MANIFEST_FILE_SUFFIX).toString();
        return ( fn ) ;
    
public java.lang.StringgetManifestFileTemplatePath()
Returns the absolute location of the template for the given service. The type of the service must be set before calling this method, otherwise a runtime exception results.

        /* Implementation Note: This should actually come from PEFileLayout or EEFileLayout, but 
         * it is too complex to get access to PEFileLayout instance and hence this
         * (rather incorrect) approach of getting template path information is
         */
        if (NULL_VALUE.equals(getType().toString())) {
            final String msg = sm.getString("serviceTypeNotSet");
            throw new RuntimeException(msg);
        }
        final StringBuilder sb = new StringBuilder();
        sb.append(System.getProperty(SystemPropertyConstants.INSTALL_ROOT_PROPERTY));
        if (sb.charAt(sb.length() - 1) == '/")
            sb.setLength(sb.length() - 1); //strip trailing '/' if present
        sb.append("/lib/install/templates/");
        sb.append(this.getType().toString()); //Domain or NodeAgent
        sb.append(MANIFEST_FILE_TEMPL_SUFFIX); //-service.xml.template
        return ( sb.toString() );
    
public java.lang.StringgetName()
Returns the name of the SMF Service.

        return ( pairs.get(SERVICE_NAME_TN) );
    
public java.lang.StringgetOSUser()
Returns the OS-level user-id who should start and own the processes started by this service.

        return (pairs.get(OS_USER_TN) );
    
public java.lang.StringgetPasswordFilePath()
Returns the absolute path of the password file that contains asadmin authentication artifacts.

        return (pairs.get(PASSWORD_FILE_PATH_TN) );
    
public java.lang.StringgetServiceProperties()
Returns the additional properties of the Service.

return
String representing addtional properties of the service. May return default properties as well.

        return ( pairs.get(PRIVILEGES_TN) );
    
public intgetTimeoutSeconds()
Returns timeout in seconds before the master boot restarter should give up starting this service.

        final int to = Integer.parseInt(pairs.get(TIMEOUT_SECONDS_TN));
        return ( to );
    
public AppserverServiceTypegetType()
Returns the type of service as an enum AppserverServiceType, from the given String.

throws
IllegalArgumentException if the enum value in the internal data structure is not valid.
see
AppserverServiceType

        return ( AppserverServiceType.valueOf(pairs.get(SERVICE_TYPE_TN)) );
    
private booleanimportService(com.sun.enterprise.admin.servermgmt.SMFService smf)

        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 voidinit()

        pairs.put(DATE_CREATED_TN, new Date().toString());
        pairs.put(SERVICE_NAME_TN, NULL_VALUE);
        pairs.put(SERVICE_TYPE_TN, NULL_VALUE);
        pairs.put(CFG_LOCATION_TN, NULL_VALUE);
        pairs.put(ENTITY_NAME_TN, NULL_VALUE);
        pairs.put(FQSN_TN, NULL_VALUE);
        pairs.put(START_INSTANCES_TN, START_INSTANCES_DEFAULT_VAL);
        pairs.put(AS_ADMIN_PATH_TN, NULL_VALUE);
        pairs.put(AS_ADMIN_USER_TN, AS_ADMIN_USER_DEF_VAL);
        pairs.put(PASSWORD_FILE_PATH_TN, NULL_VALUE);
        pairs.put(TIMEOUT_SECONDS_TN, TIMEOUT_SECONDS_DV);
        pairs.put(OS_USER_TN, NULL_VALUE);
        pairs.put(PRIVILEGES_TN, PRIVILEGES_DEFAULT_VAL);
    
public booleanisConfigValid()
Determines if the configuration of the method is valid. When this class is constructed, appropriate defaults are used. But before attempting to create the service in the Solaris platform, it is important that the necessary configuration is done by the users via various mutator methods of this class. This method must be called to guard against some abnormal failures before creating the service. It makes sure that the caller has set all the necessary parameters reasonably. Note that it does not validate the actual values.

throws
RuntimeException if the configuration is not valid
return
true if the configuration is valid, an exception is thrown otherwise

        final Set<String> keys = pairs.keySet();
        for (final String k : keys) {
            final boolean aNullValue = NULL_VALUE.equals(pairs.get(k));
            if (aNullValue) {
                final String msg = sm.getString("smfTokenNeeded", k, pairs.get(k));
                throw new RuntimeException(msg);
            }
        }
        final File mf = new File(getManifestFileTemplatePath());
        if (!mf.exists()) {
            final String msg = sm.getString("serviceTemplateNotFound", getManifestFileTemplatePath());
            throw new RuntimeException(msg);
        }
        return ( true );
    
private booleanisUserSmfAuthorized(java.lang.String user, java.lang.StringBuilder auths)

          boolean authorized = false;
          String path2Auths = "auths";
          String at = ",";
          final String AUTH1 = "solaris.*";
          final String AUTH2 = "solaris.smf.*";
          final String AUTH3 = "solaris.smf.modify";
          if (System.getProperty("PATH_2_AUTHS") != null)
              path2Auths = System.getProperty("PATH_2_AUTHS");
          if (System.getProperty("AUTH_TOKEN") != null)
              at = System.getProperty("AUTH_TOKEN");
          try {
              final String[] cmd = new String[]{path2Auths, user};
              ProcessExecutor pe = new ProcessExecutor(cmd);
              pe.setExecutionRetentionFlag(true);
              pe.execute();
              auths.append(pe.getLastExecutionOutput());
              final StringTokenizer st = new StringTokenizer(pe.getLastExecutionOutput(), at);
              while (st.hasMoreTokens()) {
                  String t = st.nextToken();
                  if (t != null)
                      t = t.trim();
                  if (AUTH1.equals(t) || AUTH2.equals(t) || AUTH3.equals(t)) {
                      authorized = true;
                      break;
                  }
              }
              return ( authorized );
         } catch(Exception e) {
             throw new RuntimeException(e);
         }
    
private com.sun.enterprise.admin.util.TokenValueSetmap2Set(java.util.Map map)

        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 voidprintOut(java.lang.String s)

        System.out.println(s);
    
private java.util.Setps2Pairs(java.lang.String cds)

        final StringTokenizer p = new StringTokenizer(cds, SP_DELIMITER);
        final Set<String> tokens = new HashSet<String>();
        while (p.hasMoreTokens()) {
            tokens.add(p.nextToken());
        }
        return ( tokens );
    
private booleanserviceNameExists(java.lang.String sn)

        boolean exists = false;
        try {
            final String[] cmd = new String[] {"/usr/bin/svcs", sn};
            ProcessExecutor pe = new ProcessExecutor(cmd);
            pe.setExecutionRetentionFlag(true);
            pe.execute();
            exists = true;
        } catch(final Exception e) {
            //returns a non-zero status -- the service does not exist, status is already set
        }
        return ( exists );
    
public voidsetAsadminPath(java.lang.String path)
Sets the absolute path to the asadmin script. May not be null.

        if (path == null)
            throw new IllegalArgumentException(nullArgMsg);
        if (! new File(path).exists()) {
            final String msg = sm.getString("doesNotExist", path);
            throw new IllegalArgumentException(msg);
        }
        pairs.put(AS_ADMIN_PATH_TN, path);
    
public voidsetDate(java.lang.String date)
Sets the date as the date when this service is created.

param
date String representation of the date
throws
IllegalArgumentException if the parameter is null

        if (date == null)
            throw new IllegalArgumentException(nullArgMsg);
        pairs.put(DATE_CREATED_TN, date);
    
public voidsetFQSN()
Sets the so-called Fully Qualified Service Name for this service. Note that there is no parameter accepted by this method. This is because the Fully Qualified Service Name is a function of name and location. The callers are expected to call this method once name and location is set on this service.

        //note that this is function of name and location
        //note that it is a programming error to call this method b4 setName()
        assert !NULL_VALUE.equals(pairs.get(SERVICE_NAME_TN)):"Internal: Caller tried to call this method before setName()";
        final String underscored = pairs.get(ENTITY_NAME_TN) + pairs.get(CFG_LOCATION_TN).replace('/", '_");
        pairs.put(FQSN_TN, underscored);
    
public voidsetLocation(java.lang.String cfgLocation)
Sets the location to the parent of given location. The location is treated as absolute and hence caller must ensure that it passes the absolute location.

        if (cfgLocation == null)
            throw new IllegalArgumentException(nullArgMsg);
        final File cf = FileUtils.safeGetCanonicalFile(new File(cfgLocation));
        pairs.put(CFG_LOCATION_TN, cf.getParent());
        pairs.put(ENTITY_NAME_TN, cf.getName());
    
public voidsetName(java.lang.String name)
Sets the name of the service. Parameter may not be null, an IllegalArgumentException results otherwise.

        if (name == null)
            throw new IllegalArgumentException(nullArgMsg);
        final String fullName = SERVICE_NAME_PREFIX + name;
        if (serviceNameExists(fullName)) {
            final String msg = sm.getString("serviceNameExists", fullName);
            throw new IllegalArgumentException(msg);
        }
        pairs.put(SERVICE_NAME_TN, fullName);
    
public voidsetOSUser()
Sets the OS-level user-id who should start and own the processes started by this service. This user is the same as the value returned by System.getProperty("user.name"). The idea is that the method is called by the user who actually wants to own the service.

throws
IllegalArgumentException if the user can not modify MANIFEST_HOME
throws
IllegalArgumentException if solaris.smf.modify Authorization is not implied by the authorizations available for the user.

        final String user = System.getProperty("user.name");
        String msg;
        if (!canCreateManifest()) {
            msg = sm.getString("noPermissionToCreateManifest", user, MANIFEST_HOME);
            throw new IllegalArgumentException(msg);
        }
        final StringBuilder auths =  new StringBuilder();
        if (!isUserSmfAuthorized(user, auths)) {
            msg = sm.getString("noSmfAuth", user, auths);
            throw new IllegalArgumentException(msg);
        }
        pairs.put(OS_USER_TN, user);
    
public voidsetPasswordFilePath(java.lang.String path)
Sets the absolute path of the password file that contains asadmin authentication artifacts. Parameter may not be null.

        if (path == null)
            throw new IllegalArgumentException(nullArgMsg);
        String msg = null;
        if (!new File(path).exists()) {
            msg = sm.getString("doesNotExist", path);
            throw new IllegalArgumentException(msg);
        }
        final String cp = FileUtils.safeGetCanonicalPath(new File(path));
        final Map<String, String> tv = new HashMap<String, String> ();
        if (!fileContainsToken(cp, AS_ADMIN_USER_TN, tv)) {
            msg = sm.getString("missingParamsInFile", cp, AS_ADMIN_USER_TN);
            throw new IllegalArgumentException(msg);
        }
        if (!fileContainsToken(cp, AS_ADMIN_PASSWORD_TN, tv)) {
            msg = sm.getString("missingParamsInFile", cp, AS_ADMIN_PASSWORD_TN);
            throw new IllegalArgumentException(msg);
        }
        if (!fileContainsToken(path, AS_ADMIN_MASTERPASSWORD_TN, tv)) {
            msg = sm.getString("missingParamsInFile", cp, AS_ADMIN_MASTERPASSWORD_TN);
            throw new IllegalArgumentException(msg);
        }
        pairs.put(AS_ADMIN_USER_TN, tv.get(AS_ADMIN_USER_TN));
        pairs.put(PASSWORD_FILE_PATH_TN, cp);
    
public voidsetServiceProperties(java.lang.String cds)
Sets the additional service properties that are specific to it.

param
must be a colon separated String, if not null. No effect, if null is passed.

        /* For now, we have to take care of only net_privaddr privilege property.
         * Additional properties will result in additional tokens being replaced.
         * A null value for parameter results in setting the basic privilege property.
         */
        if (cds != null) {
            final Set<String> props = ps2Pairs(cds);
            if (props.contains(NETADDR_PRIV_VAL)) {
                pairs.put(PRIVILEGES_TN, BASIC_NETADDR_PRIV_VAL); // you get both basic, netaddr_priv
            }
            if (props.contains(NO_START_INSTANCES_PROPERTY)) {
               pairs.put(START_INSTANCES_TN, Boolean.FALSE.toString());
            }
        }
    
public voidsetTimeoutSeconds(int number)
Sets timeout in seconds before the master boot restarter should give up starting this service.

param
number a non-negative integer representing timeout. A value of zero implies infinite timeout.

        Integer to = Integer.valueOf(number);
        if (to < 0) {
            final String msg = sm.getString("invalidTO", number);
            throw new IllegalArgumentException(msg);
        }
        pairs.put(TIMEOUT_SECONDS_TN, to.toString() );
    
public voidsetTrace(boolean trace)
Sets the trace information for debuggging purposes.

        this.trace = trace;
    
public voidsetType(AppserverServiceType type)
Sets the type of the service to the given value in the enum.

see
AppserverServiceType

        pairs.put(SERVICE_TYPE_TN, type.toString());
    
public java.lang.StringtoString()
Returns a String representation of the SMFService. It contains a new-line separated "name=value" String that contains the name and value of each of of the tokens that were set in the service.

return
a String according to above description, never returns null

        /* toString method useful for debugging */
        final StringBuilder sb = new StringBuilder();
        final String[] ka = new String[pairs.size()];
        Arrays.sort(pairs.keySet().toArray(ka));
        for (final String n : ka) {
            sb.append(n).append("=").append(pairs.get(n)).append(System.getProperty("line.separator"));
        }
        return ( sb.toString() );
    
private voidtokenReplaceTemplateAtDestination(com.sun.enterprise.admin.servermgmt.SMFService smf)

        final LineTokenReplacer tr = new LineTokenReplacer(map2Set(smf.tokensAndValues()));
        tr.replace(smf.getManifestFileTemplatePath(), smf.getManifestFilePath());
        if (trace)
            printOut("Manifest configured: " + smf.getManifestFilePath());
    
public java.util.MaptokensAndValues()
Returns the tokens and values of the service as a map. Note that a copy is returned.

return
a copy of tokens and values

        return ( new HashMap<String, String> (pairs) ); //send only copy
    
private voidvalidateManifest(java.lang.String manifestPath)

        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 voidvalidateService(com.sun.enterprise.admin.servermgmt.SMFService smf)

        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);