001    package org.hackystat.sensorshell.usermap;
002    
003    import java.io.File;
004    import java.util.HashMap;
005    import java.util.Map;
006    import java.util.Properties;
007    import java.util.Set;
008    
009    import org.hackystat.sensorshell.SensorShell;
010    import org.hackystat.sensorshell.SensorShellProperties;
011    import org.hackystat.sensorshell.usermap.UserMap.UserMapKey;
012    
013    /**
014     * Allows for lazy instantiation of SensorShells for user tool accounts. This class abstracts the
015     * use of the UserMap class so that sensors for applicable tool sensors won't have to manage it.
016     * <p>
017     * The <code>SensorShellMap</code> is meant to only derive SensorShells for a specific tool.
018     * Queries for SensorShells are done by giving an account name to the <code>getUserShell</code>
019     * method. This account name must be specific to the tool of the <code>SensorShellMap</code>
020     * instance.
021     * <p>
022     * Note that the "tool" name is used in a case-insensitive fashion.
023     * 
024     * @author Burt Leung, Julie Ann Sakuda (v8 port)
025     */
026    public class SensorShellMap {
027    
028      /** The tool that this SensorShellMap will return SensorShells for. */
029      private String tool;
030    
031      /** Mapping of Tool specific user accounts to their Hackystat information. */
032      private UserMap userMap;
033    
034      /** Map of Tool specific tool accounts to their SensorShells. */
035      private Map<String, SensorShell> toolAccountsToShells = new HashMap<String, SensorShell>();
036    
037      /**
038       * Instantiate this class which initializes the UserMap used to get SensorShells for users and
039       * also sets the Hackystat host for the SensorShells.
040       * 
041       * @param tool The specific tool that this SensorShellMap will provide SensorShells for.
042       * @throws SensorShellMapException Indicates that the usermaps.xml file is not found.
043       */
044      public SensorShellMap(String tool) throws SensorShellMapException {
045        // Ensure valid argument
046        if (tool == null || tool.length() == 0) {
047          throw new SensorShellMapException("Error: tool is null or empty string.");
048        }
049        this.tool = tool.trim();
050        this.userMap = new UserMap();
051      }
052    
053      /**
054       * A package private constructor meant to be used only by Junit test cases.
055       * 
056       * @param tool The specific tool that this SensorShellMap will provide SensorShells for.
057       * @param userMapFile The UserMap.xml file.
058       * @throws SensorShellMapException Indicates that the UserMap.xml file is not found.
059       */
060      public SensorShellMap(String tool, File userMapFile)
061          throws SensorShellMapException {
062        this.tool = tool;
063        this.userMap = new UserMap(userMapFile);
064      }
065    
066      /**
067       * Returns true if toolAccount is known so that a corresponding SensorShell can be retrieved.
068       * 
069       * @param toolAccount The toolAccount for the tool in this instance, such as "johnson".
070       * @return True if toolAccount is known, otherwise false.
071       */
072      public boolean hasUserShell(String toolAccount) {
073        if (toolAccount == null || toolAccount.length() == 0) {
074          return false;
075        }
076        else {
077          return this.userMap.hasUser(this.tool, toolAccount.trim());
078        }
079      }
080      
081      /**
082       * Returns the set of tool account names associated with this tool in the usermaps file.
083       * @param tool The tool of interest.
084       * @return The known tool account names for this tool.
085       */
086      public Set<String> getToolAccounts(String tool) {
087        return this.userMap.getToolAccounts(tool);
088      }
089      
090      /**
091       * Returns the UserMap file name associated with this SensorShellMap.
092       * This file may or may not exist.
093       * @return The usermap file name associated with this SensorShellMap. 
094       */
095      public String getUserMapFile() {
096        return this.userMap.getUserMapFile();
097      }
098      
099      /**
100       * Validates the hackystat user, password, and sensorbase associated with tool. 
101       * Throws an exception if the sensorbase cannot be contacted and/or if the user/password
102       * combination is not valid for the associated sensorbase. 
103       * @param tool The tool of interest. 
104       * @throws SensorShellMapException Thrown if user map info cannot be validated. 
105       */
106      public void validateHackystatInfo(String tool) throws SensorShellMapException {
107        this.userMap.validateHackystatUsers(tool);
108      }
109    
110      /**
111       * Gets the SensorShell instance for a Hackystat user with an account for the given tool. Assumes
112       * that toolAccount is known and will map to a userKey; use hasUserShell() to check whether this
113       * is true before calling this method. Instantiates the SensorShell instance if it is not yet
114       * available.
115       * 
116       * @param toolAccount The name of the account for the given tool. This is not the same as the
117       *          Hackystat account name although it may be the same.
118       * @return The SensorShell instance for the specific Hackystat user.
119       * @throws SensorShellMapException When the user account and/or tool is undefined.
120       */
121      public SensorShell getUserShell(String toolAccount) throws SensorShellMapException {
122       return getUserShell(toolAccount, null);
123      }
124      
125      /**
126       * Gets the SensorShell instance for a Hackystat user with an account for the given tool. Assumes
127       * that toolAccount is known and will map to a userKey; use hasUserShell() to check whether this
128       * is true before calling this method. Instantiates the SensorShell instance if it is not yet
129       * available.
130       * 
131       * @param toolAccount The name of the account for the given tool. This is not the same as the
132       *          Hackystat account name although it may be the same.
133       * @param properties A properties instance holding SensorShell properties to be used to 
134       * initialize the underlying SensorShell if it requires instantiation. If null, then no 
135       * additional properties are required.          
136       * @return The SensorShell instance for the specific Hackystat user.
137       * @throws SensorShellMapException When the user account and/or tool is undefined.
138       */
139      public SensorShell getUserShell(String toolAccount, Properties properties) 
140      throws SensorShellMapException {
141        // Check argument that it is valid
142        if (toolAccount == null || toolAccount.length() == 0) {
143          throw new SensorShellMapException("Error: toolAccount is null or the empty string.");
144        }
145        String trimmedToolAccount = toolAccount.trim();
146        try {
147          String user = this.userMap.get(this.tool, trimmedToolAccount, UserMapKey.USER);
148          String password = this.userMap.get(this.tool, trimmedToolAccount, UserMapKey.PASSWORD);
149          String host = this.userMap.get(this.tool, trimmedToolAccount, UserMapKey.SENSORBASE);
150          // If we haven't instantiated this shell yet, then do it now.
151          if (this.toolAccountsToShells.get(toolAccount) == null) {
152            // First, build the SensorShellProperties instance. 
153            // If properties is null, then call the three arg constructor. otherwise pass them in.
154            // Note: properties do not override user preferences as set in sensorshell.properties.
155            SensorShellProperties sensorProps = (properties == null) ? 
156                new SensorShellProperties(host, user, password) :
157                  new SensorShellProperties(host, user, password, properties, false) ;
158            // Now, instantiate the non-interactive SensorShell.
159            SensorShell userShell = new SensorShell(sensorProps, false, this.tool + "-" + user);
160            this.toolAccountsToShells.put(trimmedToolAccount, userShell);
161          }
162          // Now return the SensorShell.
163          return this.toolAccountsToShells.get(trimmedToolAccount);
164        }
165        catch (Exception e) {
166          throw new SensorShellMapException("Error getting SensorShell for " + toolAccount, e);
167        }
168      }
169    }