You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sw...@apache.org on 2014/07/01 22:38:03 UTC

git commit: AMBARI-6344. Views: Add optional attribute to in view.xml.

Repository: ambari
Updated Branches:
  refs/heads/trunk d853a99a8 -> 01e9e7607


AMBARI-6344. Views: Add <mask> optional attribute to <parameter> in view.xml.


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/01e9e760
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/01e9e760
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/01e9e760

Branch: refs/heads/trunk
Commit: 01e9e76079f4fb5aeffa5ce059644f16296f5291
Parents: d853a99
Author: Siddharth Wagle <sw...@hortonworks.com>
Authored: Tue Jul 1 13:20:37 2014 -0700
Committer: Siddharth Wagle <sw...@hortonworks.com>
Committed: Tue Jul 1 13:39:17 2014 -0700

----------------------------------------------------------------------
 .../internal/ViewVersionResourceProvider.java   | 15 ++--
 .../ambari/server/orm/entities/ViewEntity.java  | 27 +++++++
 .../orm/entities/ViewParameterEntity.java       | 24 ++++++
 .../server/upgrade/UpgradeCatalog170.java       |  6 ++
 .../ambari/server/view/DefaultMasker.java       | 48 ++++++++++++
 .../ambari/server/view/ViewContextImpl.java     | 82 +++++++++++++++-----
 .../apache/ambari/server/view/ViewRegistry.java | 48 +++++++++---
 .../view/configuration/ParameterConfig.java     | 14 ++++
 .../server/view/configuration/ViewConfig.java   | 45 ++++++++++-
 .../main/resources/Ambari-DDL-MySQL-CREATE.sql  |  4 +-
 .../main/resources/Ambari-DDL-Oracle-CREATE.sql |  4 +-
 .../resources/Ambari-DDL-Postgres-CREATE.sql    |  4 +-
 .../Ambari-DDL-Postgres-EMBEDDED-CREATE.sql     |  4 +-
 .../server/upgrade/UpgradeCatalog170Test.java   | 43 +++++++++-
 .../ambari/server/view/DefaultMaskerTest.java   | 47 +++++++++++
 .../ambari/server/view/ViewContextImplTest.java |  9 ++-
 .../view/configuration/ParameterConfigTest.java |  9 +++
 .../view/configuration/ViewConfigTest.java      |  8 ++
 ambari-views/pom.xml                            | 21 ++---
 .../org/apache/ambari/view/MaskException.java   | 33 ++++++++
 .../java/org/apache/ambari/view/Masker.java     | 43 ++++++++++
 .../ambari/view/PersistenceException.java       |  2 +-
 .../org/apache/ambari/view/ViewDefinition.java  |  7 ++
 23 files changed, 490 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java
index 485eb04..5793a1b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ViewVersionResourceProvider.java
@@ -44,12 +44,13 @@ public class ViewVersionResourceProvider extends AbstractResourceProvider {
   /**
    * View property id constants.
    */
-  public static final String VIEW_NAME_PROPERTY_ID    = "ViewVersionInfo/view_name";
-  public static final String VIEW_VERSION_PROPERTY_ID = "ViewVersionInfo/version";
-  public static final String LABEL_PROPERTY_ID        = "ViewVersionInfo/label";
-  public static final String VERSION_PROPERTY_ID      = "ViewVersionInfo/version";
-  public static final String PARAMETERS_PROPERTY_ID   = "ViewVersionInfo/parameters";
-  public static final String ARCHIVE_PROPERTY_ID      = "ViewVersionInfo/archive";
+  public static final String VIEW_NAME_PROPERTY_ID      = "ViewVersionInfo/view_name";
+  public static final String VIEW_VERSION_PROPERTY_ID   = "ViewVersionInfo/version";
+  public static final String LABEL_PROPERTY_ID          = "ViewVersionInfo/label";
+  public static final String VERSION_PROPERTY_ID        = "ViewVersionInfo/version";
+  public static final String PARAMETERS_PROPERTY_ID     = "ViewVersionInfo/parameters";
+  public static final String ARCHIVE_PROPERTY_ID        = "ViewVersionInfo/archive";
+  public static final String MASKER_CLASS_PROPERTY_ID   = "ViewVersionInfo/masker_class";
 
   /**
    * The key property ids for a view resource.
@@ -71,6 +72,7 @@ public class ViewVersionResourceProvider extends AbstractResourceProvider {
     propertyIds.add(VERSION_PROPERTY_ID);
     propertyIds.add(PARAMETERS_PROPERTY_ID);
     propertyIds.add(ARCHIVE_PROPERTY_ID);
+    propertyIds.add(MASKER_CLASS_PROPERTY_ID);
   }
 
 
@@ -123,6 +125,7 @@ public class ViewVersionResourceProvider extends AbstractResourceProvider {
             setResourceProperty(resource, PARAMETERS_PROPERTY_ID,
                 viewDefinition.getConfiguration().getParameters(), requestedIds);
             setResourceProperty(resource, ARCHIVE_PROPERTY_ID, viewDefinition.getArchive(), requestedIds);
+            setResourceProperty(resource, MASKER_CLASS_PROPERTY_ID, viewDefinition.getMask(), requestedIds);
 
             resources.add(resource);
           }

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
index eaf2589..a26e5e7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewEntity.java
@@ -94,6 +94,13 @@ public class ViewEntity implements ViewDefinition {
   private String archive;
 
   /**
+   * The masker class for parameters.
+   */
+  @Column
+  @Basic
+  private String mask;
+
+  /**
    * The list of view parameters.
    */
   @OneToMany(cascade = CascadeType.ALL, mappedBy = "view")
@@ -202,6 +209,8 @@ public class ViewEntity implements ViewDefinition {
     this.name    = getViewName(configuration.getName(), version);
     this.label   = configuration.getLabel();
     this.version = version;
+
+    this.mask    = configuration.getMasker();
     this.icon    = configuration.getIcon();
     this.icon64  = configuration.getIcon64();
 
@@ -580,6 +589,24 @@ public class ViewEntity implements ViewDefinition {
     return view;
   }
 
+  /**
+   * Set the mask class name.
+   *
+   * @param mask the mask class name
+   */
+  public void setMask(String mask) {
+    this.mask = mask;
+  }
+
+  /**
+   * Get the mask class name.
+   *
+   * @return the mask class name.
+   */
+  public String getMask() {
+    return mask;
+  }
+
 
   // ----- helper methods ----------------------------------------------------
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewParameterEntity.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewParameterEntity.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewParameterEntity.java
index b3a7320..0c4c70f 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewParameterEntity.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/entities/ViewParameterEntity.java
@@ -58,6 +58,13 @@ public class ViewParameterEntity {
   @Basic
   private char required;
 
+  /**
+   * Indicates whether or not the parameter is masked when persisted.
+   */
+  @Column
+  @Basic
+  private char masked;
+
   @ManyToOne
   @JoinColumn(name = "view_name", referencedColumnName = "view_name", nullable = false)
   private ViewEntity view;
@@ -138,6 +145,23 @@ public class ViewParameterEntity {
   }
 
   /**
+   * Determine whether or not the parameter is masked.
+   *
+   * @return true if parameter is masked
+   */
+  public boolean isMasked() {
+    return masked == 'y' || masked == 'Y';
+  }
+
+  /**
+   * Set the flag which indicate whether or not the parameter is masked
+   * @param masked the masked flag; true if the parameter is masked
+   */
+  public void setMasked(boolean masked) {
+    this.masked = (masked ? 'Y' : 'N');
+  }
+
+  /**
    * Get the associated view entity.
    *
    * @return the view entity

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
index 029e98c..50087e5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/upgrade/UpgradeCatalog170.java
@@ -65,6 +65,12 @@ public class UpgradeCatalog170 extends AbstractUpgradeCatalog {
     DBAccessor.DBColumnInfo clusterConfigAttributesColumn = new DBAccessor.DBColumnInfo(
         "config_attributes", String.class, 32000, null, true);
     dbAccessor.addColumn("clusterconfig", clusterConfigAttributesColumn);
+
+    // Add columns
+    dbAccessor.addColumn("viewmain", new DBAccessor.DBColumnInfo("mask",
+      String.class, 255, null, true));
+    dbAccessor.addColumn("viewparameter", new DBAccessor.DBColumnInfo("masked",
+      Character.class, 1, null, true));
   }
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/view/DefaultMasker.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/DefaultMasker.java b/ambari-server/src/main/java/org/apache/ambari/server/view/DefaultMasker.java
new file mode 100644
index 0000000..704ff7d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/DefaultMasker.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.view;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.ambari.view.MaskException;
+import org.apache.ambari.view.Masker;
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * Provides simple masking of view parameters.
+ */
+public class DefaultMasker implements Masker {
+
+  @Override
+  public String mask(String value) throws MaskException {
+    try {
+      return Base64.encodeBase64String(value.getBytes("UTF-8"));
+    } catch (UnsupportedEncodingException e) {
+      throw new MaskException("UTF-8 is not supported", e);
+    }
+  }
+
+  @Override
+  public String unmask(String value) throws MaskException {
+    try {
+      return new String(Base64.decodeBase64(value), "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      throw new MaskException("UTF-8 is not supported", e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
index e914c75..6426575 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewContextImpl.java
@@ -38,8 +38,6 @@ import org.apache.ambari.view.events.Listener;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.Velocity;
 import org.apache.velocity.exception.ParseErrorException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -51,6 +49,15 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.ambari.server.view.configuration.ParameterConfig;
+import org.apache.ambari.server.view.configuration.ViewConfig;
+import org.apache.ambari.view.MaskException;
+import org.apache.ambari.view.Masker;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 
 /**
  * View context implementation.
@@ -58,6 +65,11 @@ import java.util.Map;
 public class ViewContextImpl implements ViewContext, ViewController {
 
   /**
+   * Logger.
+   */
+  private static final Log LOG = LogFactory.getLog(ViewContextImpl.class);
+
+  /**
    * The associated view definition.
    */
   private final ViewEntity viewEntity;
@@ -82,14 +94,12 @@ public class ViewContextImpl implements ViewContext, ViewController {
    */
   private DataStore dataStore = null;
 
-  private final VelocityContext velocityContext;
-
-
-  // ----- Constants ---------------------------------------------------------
-
-  protected final static Logger LOG =
-      LoggerFactory.getLogger(ViewContext.class);
+  /**
+   * Masker for properties.
+   */
+  private Masker masker;
 
+  private final VelocityContext velocityContext;
 
   // ---- Constructors -------------------------------------------------------
 
@@ -118,6 +128,7 @@ public class ViewContextImpl implements ViewContext, ViewController {
     this.viewInstanceEntity = viewInstanceEntity;
     this.viewRegistry       = viewRegistry;
     this.streamProvider     = ViewURLStreamProvider.getProvider();
+    this.masker             = getMasker(viewEntity.getClassLoader(), viewEntity.getConfiguration());
     this.velocityContext    = initVelocityContext();
   }
 
@@ -147,18 +158,42 @@ public class ViewContextImpl implements ViewContext, ViewController {
   public Map<String, String> getProperties() {
     if (viewInstanceEntity == null) {
       return null;
-    }
-    Map<String, String> properties = viewInstanceEntity.getPropertyMap();
-    String rawValue;
-    for (String key : properties.keySet()) {
-      rawValue = properties.get(key);
-      try {
-        properties.put(key, parameterize(rawValue));
-      } catch (ParseErrorException ex) {
-        LOG.warn(String.format("Error during parsing '%s' parameter. Leaving original value.", key));
+    } else {
+      Map<String, String> properties = viewInstanceEntity.getPropertyMap();
+
+      // unmasking
+      for (Entry<String, String> entry: properties.entrySet()) {
+        ParameterConfig parameterConfig = null;
+        for (ParameterConfig paramConfig : viewEntity.getConfiguration().getParameters()) {
+          if (StringUtils.equals(paramConfig.getName(), entry.getKey())) {
+            parameterConfig = paramConfig;
+            break;
+          }
+        }
+        if (parameterConfig == null || !parameterConfig.isMasked()) {
+          properties.put(entry.getKey(), entry.getValue());
+        } else {
+          try {
+            properties.put(entry.getKey(), masker.unmask(entry.getValue()));
+          } catch (MaskException e) {
+            LOG.error("Failed to unmask view property", e);
+          }
+        }
+      }
+
+      // parametrizing
+
+      String rawValue;
+      for (String key : properties.keySet()) {
+        rawValue = properties.get(key);
+        try {
+          properties.put(key, parameterize(rawValue));
+        } catch (ParseErrorException ex) {
+          LOG.warn(String.format("Error during parsing '%s' parameter. Leaving original value.", key));
+        }
       }
+      return Collections.unmodifiableMap(properties);
     }
-    return Collections.unmodifiableMap(properties);
   }
 
   @Override
@@ -270,6 +305,14 @@ public class ViewContextImpl implements ViewContext, ViewController {
     }
   }
 
+  private Masker getMasker(ClassLoader cl, ViewConfig viewConfig) {
+    try {
+      return viewConfig.getMaskerClass(cl).newInstance();
+    } catch (Exception e) {
+      throw new InstantiationError("Could not create masker instance.");
+    }
+  }
+
   /**
    * Parameterize string using VelocityContext instance
    *
@@ -316,7 +359,6 @@ public class ViewContextImpl implements ViewContext, ViewController {
     return context;
   }
 
-
   // ----- Inner class : ViewURLStreamProvider -------------------------------
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
index 33485a0..849da64 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewRegistry.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.view;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
+
 import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
 import org.apache.ambari.server.api.resources.SubResourceDefinition;
 import org.apache.ambari.server.api.resources.ViewExternalSubResourceDefinition;
@@ -43,6 +44,8 @@ import org.apache.ambari.server.view.configuration.PersistenceConfig;
 import org.apache.ambari.server.view.configuration.PropertyConfig;
 import org.apache.ambari.server.view.configuration.ResourceConfig;
 import org.apache.ambari.server.view.configuration.ViewConfig;
+import org.apache.ambari.view.MaskException;
+import org.apache.ambari.view.Masker;
 import org.apache.ambari.view.SystemException;
 import org.apache.ambari.view.View;
 import org.apache.ambari.view.ViewContext;
@@ -50,6 +53,7 @@ import org.apache.ambari.view.ViewDefinition;
 import org.apache.ambari.view.ViewResourceHandler;
 import org.apache.ambari.view.events.Event;
 import org.apache.ambari.view.events.Listener;
+import org.apache.commons.lang.StringUtils;
 import org.eclipse.jetty.webapp.WebAppContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -57,6 +61,7 @@ import org.slf4j.LoggerFactory;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
+
 import java.beans.IntrospectionException;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -203,7 +208,7 @@ public class ViewRegistry {
   }
 
   /**
-   * Get the instance definition for the given view nam,e and instance name.
+   * Get the instance definition for the given view name and instance name.
    *
    * @param viewName      the view name
    * @param version       the version
@@ -338,7 +343,7 @@ public class ViewRegistry {
 
                 for (InstanceConfig instanceConfig : viewConfig.getInstances()) {
                   try {
-                    instanceDefinitions.add(createViewInstanceDefinition(viewDefinition, instanceConfig));
+                    instanceDefinitions.add(createViewInstanceDefinition(viewConfig, viewDefinition, instanceConfig));
                   } catch (Exception e) {
                     LOG.error("Caught exception adding view instance for view " +
                         viewDefinition.getViewName(), e);
@@ -603,6 +608,7 @@ public class ViewRegistry {
       viewParameterEntity.setName(parameterConfiguration.getName());
       viewParameterEntity.setDescription(parameterConfiguration.getDescription());
       viewParameterEntity.setRequired(parameterConfiguration.isRequired());
+      viewParameterEntity.setMasked(parameterConfiguration.isMasked());
       viewParameterEntity.setViewEntity(viewDefinition);
       parameters.add(viewParameterEntity);
     }
@@ -658,18 +664,32 @@ public class ViewRegistry {
       view = getView(viewConfig.getViewClass(cl), new ViewContextImpl(viewDefinition, this));
     }
     viewDefinition.setView(view);
+    viewDefinition.setMask(viewConfig.getMasker());
 
     return viewDefinition;
   }
 
   // create a new view instance definition
-  protected ViewInstanceEntity createViewInstanceDefinition(ViewEntity viewDefinition, InstanceConfig instanceConfig)
-      throws ClassNotFoundException, IllegalStateException {
+  protected ViewInstanceEntity createViewInstanceDefinition(ViewConfig viewConfig, ViewEntity viewDefinition, InstanceConfig instanceConfig)
+      throws ClassNotFoundException, IllegalStateException, MaskException {
     ViewInstanceEntity viewInstanceDefinition =
         new ViewInstanceEntity(viewDefinition, instanceConfig);
 
+    Masker masker = getMasker(viewConfig.getMaskerClass(viewDefinition.getClassLoader()));
     for (PropertyConfig propertyConfig : instanceConfig.getProperties()) {
-      viewInstanceDefinition.putProperty(propertyConfig.getKey(), propertyConfig.getValue());
+      ParameterConfig parameterConfig = null;
+      for (ParameterConfig paramConfig : viewConfig.getParameters()) {
+        if (StringUtils.equals(paramConfig.getName(), propertyConfig.getKey())) {
+          parameterConfig = paramConfig;
+          break;
+        }
+      }
+      if (parameterConfig != null && parameterConfig.isMasked()) {
+        viewInstanceDefinition.putProperty(propertyConfig.getKey(),
+            masker.mask(propertyConfig.getValue()));
+      } else {
+        viewInstanceDefinition.putProperty(propertyConfig.getKey(), propertyConfig.getValue());
+      }
     }
     viewInstanceDefinition.validate(viewDefinition);
 
@@ -786,6 +806,16 @@ public class ViewRegistry {
     return viewInstanceInjector.getInstance(clazz);
   }
 
+  // create masker from given class; probably replace with injector later
+  private static Masker getMasker(Class<? extends Masker> clazz) {
+    try {
+      return clazz.newInstance();
+    } catch (Exception e) {
+      LOG.error("Could not create masker instance", e);
+    }
+    return null;
+  }
+
   // remove undeployed views from the ambari db
   private void removeUndeployedViews() {
     for (ViewEntity viewEntity : viewDAO.findAll()) {
@@ -881,7 +911,7 @@ public class ViewRegistry {
   }
 
   // extract the given view archive to the given archive directory
-  private ClassLoader extractViewArchive(File viewArchive, File archiveDir) 
+  private ClassLoader extractViewArchive(File viewArchive, File archiveDir)
       throws IOException {
 
     // Skip if the archive has already been extracted
@@ -890,7 +920,7 @@ public class ViewRegistry {
       String archivePath = archiveDir.getAbsolutePath();
 
       LOG.info("Creating archive folder " + archivePath + ".");
-      
+
       if (archiveDir.mkdir()) {
         JarFile     viewJarFile = helper.getJarFile(viewArchive);
         Enumeration enumeration = viewJarFile.entries();
@@ -933,7 +963,7 @@ public class ViewRegistry {
   }
 
   // get a class loader for the given archive directory
-  private ClassLoader getArchiveClassLoader(File archiveDir) 
+  private ClassLoader getArchiveClassLoader(File archiveDir)
       throws MalformedURLException {
 
     String    archivePath = archiveDir.getAbsolutePath();
@@ -960,7 +990,7 @@ public class ViewRegistry {
       }
     }
 
-    // include the archive directory 
+    // include the archive directory
     urlList.add(archiveDir.toURI().toURL());
 
     return URLClassLoader.newInstance(urlList.toArray(new URL[urlList.size()]));

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ParameterConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ParameterConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ParameterConfig.java
index 97c9e22..827b5e7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ParameterConfig.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ParameterConfig.java
@@ -42,6 +42,11 @@ public class ParameterConfig {
   private boolean required;
 
   /**
+   * Indicates whether or not the parameter is masked when persisted.
+   */
+  private boolean masked;
+
+  /**
    * Get the parameter name.
    *
    * @return the name
@@ -67,4 +72,13 @@ public class ParameterConfig {
   public boolean isRequired() {
     return required;
   }
+
+  /**
+   * Indicates whether or not the parameter is masked when persisted.
+   *
+   * @return true if the parameter is masked; false otherwise
+   */
+  public boolean isMasked() {
+    return masked;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
index 1e29f5d..e084918 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/view/configuration/ViewConfig.java
@@ -18,12 +18,16 @@
 
 package org.apache.ambari.server.view.configuration;
 
+import org.apache.ambari.server.view.DefaultMasker;
+import org.apache.ambari.view.Masker;
 import org.apache.ambari.view.View;
+import org.apache.commons.lang.StringUtils;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+
 import java.util.Collections;
 import java.util.List;
 
@@ -70,6 +74,17 @@ public class ViewConfig {
   private Class<? extends View> viewClass = null;
 
   /**
+   * The masker class name for parameters.
+   */
+  @XmlElement(name="masker-class")
+  private String masker;
+
+  /**
+   * The mask class.
+   */
+  private Class<? extends Masker> maskerClass = null;
+
+  /**
    * The list of view parameters.
    */
   @XmlElement(name="parameter")
@@ -150,7 +165,7 @@ public class ViewConfig {
   /**
    * Get the view class.
    *
-   * @param cl  the class loader
+   * @param cl the class loader
    *
    * @return the view class
    *
@@ -164,6 +179,34 @@ public class ViewConfig {
   }
 
   /**
+   * Get the masker class name.
+   * @return the masker class name
+   */
+  public String getMasker() {
+    return masker;
+  }
+
+  /**
+   * Get the masker class.
+   *
+   * @param cl the class loader
+   *
+   * @return the masker class
+   *
+   * @throws ClassNotFoundException if the class can not be loaded
+   */
+  public Class<? extends Masker> getMaskerClass(ClassLoader cl) throws ClassNotFoundException {
+    if (maskerClass == null) {
+      if (StringUtils.isBlank(masker)) {
+        maskerClass = DefaultMasker.class;
+      } else {
+        maskerClass = cl.loadClass(masker).asSubclass(Masker.class);
+      }
+    }
+    return maskerClass;
+  }
+
+  /**
    * Get the list of view parameters.
    *
    * @return the list of parameters

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
index 8d73866..f12c5d1 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-MySQL-CREATE.sql
@@ -62,11 +62,11 @@ CREATE TABLE hostgroup (blueprint_name VARCHAR(255) NOT NULL, name VARCHAR(255)
 CREATE TABLE hostgroup_component (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name, name));
 CREATE TABLE blueprint_configuration (blueprint_name VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data VARCHAR(32000) NOT NULL , PRIMARY KEY(blueprint_name, type_name));
 CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
-CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), PRIMARY KEY(view_name));
+CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), mask VARCHAR(255), PRIMARY KEY(view_name));
 CREATE TABLE viewinstancedata (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(VIEW_INSTANCE_ID, NAME, USER_NAME));
 CREATE TABLE viewinstance (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));
 CREATE TABLE viewinstanceproperty (view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_name, view_instance_name, name));
-CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), PRIMARY KEY(view_name, name));
+CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), masked CHAR(1), PRIMARY KEY(view_name, name));
 CREATE TABLE viewresource (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, plural_name VARCHAR(255), id_property VARCHAR(255), subResource_names VARCHAR(255), provider VARCHAR(255), service VARCHAR(255), resource VARCHAR(255), PRIMARY KEY(view_name, name));
 CREATE TABLE viewentity (id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, class_name VARCHAR(255) NOT NULL, id_property VARCHAR(255), PRIMARY KEY(id));
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
index c8b4ba7..3620788 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Oracle-CREATE.sql
@@ -52,11 +52,11 @@ CREATE TABLE hostgroup (blueprint_name VARCHAR2(255) NOT NULL, name VARCHAR2(255
 CREATE TABLE hostgroup_component (blueprint_name VARCHAR2(255) NOT NULL, hostgroup_name VARCHAR2(255) NOT NULL, name VARCHAR2(255) NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name, name));
 CREATE TABLE blueprint_configuration (blueprint_name VARCHAR2(255) NOT NULL, type_name VARCHAR2(255) NOT NULL, config_data CLOB NOT NULL , PRIMARY KEY(blueprint_name, type_name));
 CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR2(255) NOT NULL, hostgroup_name VARCHAR2(255) NOT NULL, type_name VARCHAR2(255) NOT NULL, config_data CLOB NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
-CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), PRIMARY KEY(view_name));
+CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), mask VARCHAR(255), PRIMARY KEY(view_name));
 CREATE TABLE viewinstancedata (view_instance_id NUMBER(19), view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_instance_id, name, user_name));
 CREATE TABLE viewinstance (view_instance_id NUMBER(19), view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));
 CREATE TABLE viewinstanceproperty (view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_name, view_instance_name, name));
-CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), PRIMARY KEY(view_name, name));
+CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), masked CHAR(1), PRIMARY KEY(view_name, name));
 CREATE TABLE viewresource (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, plural_name VARCHAR(255), id_property VARCHAR(255), subResource_names VARCHAR(255), provider VARCHAR(255), service VARCHAR(255), "resource" VARCHAR(255), PRIMARY KEY(view_name, name));
 CREATE TABLE viewentity (id NUMBER(19) NOT NULL, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, class_name VARCHAR(255) NOT NULL, id_property VARCHAR(255), PRIMARY KEY(id));
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
index c020a66..8c1cf3b 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-CREATE.sql
@@ -85,11 +85,11 @@ CREATE TABLE hostgroup_component (blueprint_name VARCHAR(255) NOT NULL, hostgrou
 CREATE TABLE blueprint_configuration (blueprint_name varchar(255) NOT NULL, type_name varchar(255) NOT NULL, config_data varchar(32000) NOT NULL , PRIMARY KEY(blueprint_name, type_name));
 CREATE TABLE hostgroup_configuration (blueprint_name VARCHAR(255) NOT NULL, hostgroup_name VARCHAR(255) NOT NULL, type_name VARCHAR(255) NOT NULL, config_data TEXT NOT NULL, PRIMARY KEY(blueprint_name, hostgroup_name, type_name));
 
-CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), PRIMARY KEY(view_name));
+CREATE TABLE viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), mask VARCHAR(255), PRIMARY KEY(view_name));
 CREATE TABLE viewinstancedata (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_instance_id, name, user_name));
 CREATE TABLE viewinstance (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));
 CREATE TABLE viewinstanceproperty (view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_name, view_instance_name, name));
-CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), PRIMARY KEY(view_name, name));
+CREATE TABLE viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), masked CHAR(1), PRIMARY KEY(view_name, name));
 CREATE TABLE viewresource (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, plural_name VARCHAR(255), id_property VARCHAR(255), subResource_names VARCHAR(255), provider VARCHAR(255), service VARCHAR(255), resource VARCHAR(255), PRIMARY KEY(view_name, name));
 CREATE TABLE viewentity (id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, class_name VARCHAR(255) NOT NULL, id_property VARCHAR(255), PRIMARY KEY(id));
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
index a8b1048..6ac6558 100644
--- a/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
+++ b/ambari-server/src/main/resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql
@@ -132,11 +132,11 @@ GRANT ALL PRIVILEGES ON TABLE ambari.hostgroup_component TO :username;
 GRANT ALL PRIVILEGES ON TABLE ambari.blueprint_configuration TO :username;
 GRANT ALL PRIVILEGES ON TABLE ambari.hostgroup_configuration TO :username;
 
-CREATE TABLE ambari.viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), PRIMARY KEY(view_name));
+CREATE TABLE ambari.viewmain (view_name VARCHAR(255) NOT NULL, label VARCHAR(255), version VARCHAR(255), icon VARCHAR(255), icon64 VARCHAR(255), archive VARCHAR(255), mask VARCHAR(255), PRIMARY KEY(view_name));
 CREATE TABLE ambari.viewinstancedata (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, user_name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_instance_id, name, user_name));
 CREATE TABLE ambari.viewinstance (view_instance_id BIGINT, view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, label VARCHAR(255), description VARCHAR(255), visible CHAR(1), icon VARCHAR(255), icon64 VARCHAR(255), PRIMARY KEY(view_instance_id));
 CREATE TABLE ambari.viewinstanceproperty (view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, value VARCHAR(2000) NOT NULL, PRIMARY KEY(view_name, view_instance_name, name));
-CREATE TABLE ambari.viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), PRIMARY KEY(view_name, name));
+CREATE TABLE ambari.viewparameter (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(255), required CHAR(1), masked CHAR(1), PRIMARY KEY(view_name, name));
 CREATE TABLE ambari.viewresource (view_name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL, plural_name VARCHAR(255), id_property VARCHAR(255), subResource_names VARCHAR(255), provider VARCHAR(255), service VARCHAR(255), resource VARCHAR(255), PRIMARY KEY(view_name, name));
 CREATE TABLE ambari.viewentity (id BIGINT NOT NULL, view_name VARCHAR(255) NOT NULL, view_instance_name VARCHAR(255) NOT NULL, class_name VARCHAR(255) NOT NULL, id_property VARCHAR(255), PRIMARY KEY(id));
 GRANT ALL PRIVILEGES ON TABLE ambari.viewmain TO :username;

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog170Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog170Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog170Test.java
index 7101ef9..dfda132 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog170Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog170Test.java
@@ -19,6 +19,7 @@
 package org.apache.ambari.server.upgrade;
 
 import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 import static org.easymock.EasyMock.anyObject;
 import static org.easymock.EasyMock.capture;
@@ -58,7 +59,11 @@ public class UpgradeCatalog170Test {
     expect(configuration.getDatabaseUrl()).andReturn(Configuration.JDBC_IN_MEMORY_URL).anyTimes();
 
     Capture<DBAccessor.DBColumnInfo> clusterConfigAttributesColumnCapture = new Capture<DBAccessor.DBColumnInfo>();
+    Capture<DBAccessor.DBColumnInfo> maskColumnCapture = new Capture<DBAccessor.DBColumnInfo>();
+    Capture<DBAccessor.DBColumnInfo> maskedColumnCapture = new Capture<DBAccessor.DBColumnInfo>();
 
+    setViewExpectations(dbAccessor, maskColumnCapture);
+    setViewParameterExpectations(dbAccessor, maskedColumnCapture);
     setClusterConfigExpectations(dbAccessor, clusterConfigAttributesColumnCapture);
     dbAccessor.executeSelect(anyObject(String.class));
     expectLastCall().andReturn(resultSet).anyTimes();
@@ -78,6 +83,8 @@ public class UpgradeCatalog170Test {
     verify(dbAccessor, configuration, resultSet);
 
     assertClusterConfigColumns(clusterConfigAttributesColumnCapture);
+    assertViewColumns(maskColumnCapture);
+    assertViewParameterColumns(maskedColumnCapture);
   }
 
   @Test
@@ -125,5 +132,39 @@ public class UpgradeCatalog170Test {
     final DBAccessor dbAccessor     = createNiceMock(DBAccessor.class);
     UpgradeCatalog upgradeCatalog = getUpgradeCatalog(dbAccessor);
     Assert.assertEquals("1.6.1", upgradeCatalog.getSourceVersion());
-  }   
+  }
+
+  private void setViewExpectations(DBAccessor dbAccessor,
+                                   Capture<DBAccessor.DBColumnInfo> maskColumnCapture)
+    throws SQLException {
+
+    dbAccessor.addColumn(eq("viewmain"), capture(maskColumnCapture));
+  }
+
+  private void setViewParameterExpectations(DBAccessor dbAccessor,
+                                            Capture<DBAccessor.DBColumnInfo> maskedColumnCapture)
+    throws SQLException {
+
+    dbAccessor.addColumn(eq("viewparameter"), capture(maskedColumnCapture));
+  }
+
+  private void assertViewColumns(
+    Capture<DBAccessor.DBColumnInfo> maskColumnCapture) {
+    DBAccessor.DBColumnInfo column = maskColumnCapture.getValue();
+    assertEquals("mask", column.getName());
+    assertEquals(255, (int) column.getLength());
+    assertEquals(String.class, column.getType());
+    assertNull(column.getDefaultValue());
+    assertTrue(column.isNullable());
+  }
+
+  private void assertViewParameterColumns(
+    Capture<DBAccessor.DBColumnInfo> maskedColumnCapture) {
+    DBAccessor.DBColumnInfo column = maskedColumnCapture.getValue();
+    assertEquals("masked", column.getName());
+    assertEquals(1, (int) column.getLength());
+    assertEquals(Character.class, column.getType());
+    assertNull(column.getDefaultValue());
+    assertTrue(column.isNullable());
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/test/java/org/apache/ambari/server/view/DefaultMaskerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/DefaultMaskerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/DefaultMaskerTest.java
new file mode 100644
index 0000000..7fde6b7
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/DefaultMaskerTest.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.view;
+
+import junit.framework.Assert;
+
+import org.apache.ambari.server.view.DefaultMasker;
+import org.junit.Test;
+
+/**
+ * DefaultMasker test.
+ */
+public class DefaultMaskerTest {
+  private DefaultMasker masker = new DefaultMasker();
+
+  @Test
+  public void testMask() throws Exception {
+    final String source = "unmasked";
+    final String masked = masker.mask(source);
+    Assert.assertNotNull(masked);
+    Assert.assertTrue(masked.length() > 0);
+  }
+
+  @Test
+  public void testMaskUnmask() throws Exception {
+    final String source = "unmasked";
+    final String masked = masker.mask(source);
+    final String unmasked = masker.unmask(masked);
+    Assert.assertEquals(source, unmasked);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/test/java/org/apache/ambari/server/view/ViewContextImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewContextImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewContextImplTest.java
index 5358162..6bddf08 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewContextImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewContextImplTest.java
@@ -25,6 +25,7 @@ import org.apache.ambari.server.orm.entities.ViewEntityTest;
 import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
 import org.apache.ambari.server.view.configuration.InstanceConfig;
 import org.apache.ambari.server.view.configuration.InstanceConfigTest;
+import org.apache.ambari.server.view.configuration.ViewConfigTest;
 import org.apache.ambari.view.ResourceProvider;
 import org.junit.Assert;
 import org.junit.Test;
@@ -77,7 +78,7 @@ public class ViewContextImplTest {
     ViewInstanceEntity viewInstanceDefinition = new ViewInstanceEntity(viewDefinition, instanceConfig);
     ViewRegistry viewRegistry = createNiceMock(ViewRegistry.class);
     viewInstanceDefinition.putProperty("p1", "v1");
-    viewInstanceDefinition.putProperty("p2", "v2");
+    viewInstanceDefinition.putProperty("p2", new DefaultMasker().mask("v2"));
     viewInstanceDefinition.putProperty("p3", "v3");
 
     ViewContextImpl viewContext = new ViewContextImpl(viewInstanceDefinition, viewRegistry);
@@ -96,18 +97,22 @@ public class ViewContextImplTest {
     replay(instanceConfig);
     ViewEntity viewDefinition = createNiceMock(ViewEntity.class);
     expect(viewDefinition.getCommonName()).andReturn("View").times(2);
+    expect(viewDefinition.getClassLoader()).andReturn(ViewContextImplTest.class.getClassLoader()).anyTimes();
+    expect(viewDefinition.getConfiguration()).andReturn(ViewConfigTest.getConfig()).anyTimes();
     replay(viewDefinition);
     ViewInstanceEntity viewInstanceDefinition = createMockBuilder(ViewInstanceEntity.class)
         .addMockedMethod("getUsername")
         .addMockedMethod("getName")
+        .addMockedMethod("getViewEntity")
         .withConstructor(viewDefinition, instanceConfig).createMock();
     expect(viewInstanceDefinition.getUsername()).andReturn("User").times(1);
     expect(viewInstanceDefinition.getUsername()).andReturn("User2").times(1);
     expect(viewInstanceDefinition.getName()).andReturn("Instance").times(3);
+    expect(viewInstanceDefinition.getViewEntity()).andReturn(viewDefinition).times(1);
     replay(viewInstanceDefinition);
     ViewRegistry viewRegistry = createNiceMock(ViewRegistry.class);
     viewInstanceDefinition.putProperty("p1", "/tmp/some/path/${username}");
-    viewInstanceDefinition.putProperty("p2", "/tmp/path/$viewName");
+    viewInstanceDefinition.putProperty("p2", new DefaultMasker().mask("/tmp/path/$viewName"));
     viewInstanceDefinition.putProperty("p3", "/path/$instanceName");
     viewInstanceDefinition.putProperty("p4", "/path/to/${unspecified_parameter}");
     viewInstanceDefinition.putProperty("p5", "/path/to/${incorrect_parameter");

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ParameterConfigTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ParameterConfigTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ParameterConfigTest.java
index 7069d37..e3350bc 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ParameterConfigTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ParameterConfigTest.java
@@ -55,6 +55,15 @@ public class ParameterConfigTest {
     Assert.assertEquals(false, parameters.get(1).isRequired());
   }
 
+  @Test
+  public void testIsMasked() throws Exception {
+    List<ParameterConfig> parameters = getParameterConfigs();
+
+    Assert.assertEquals(2, parameters.size());
+    Assert.assertEquals(false, parameters.get(0).isMasked());
+    Assert.assertEquals(true, parameters.get(1).isMasked());
+  }
+
   public static List<ParameterConfig> getParameterConfigs() throws JAXBException {
     ViewConfig viewConfig = ViewConfigTest.getConfig();
     return viewConfig.getParameters ();

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
index bb4ad0c..ba40027 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/view/configuration/ViewConfigTest.java
@@ -48,6 +48,7 @@ public class ViewConfigTest {
       "    <version>1.0.0</version>\n" +
       "    <icon64>/this/is/the/icon/url/icon64.png</icon64>\n" +
       "    <icon>/this/is/the/icon/url/icon.png</icon>\n" +
+      "    <masker-class>org.apache.ambari.server.view.DefaultMasker</masker-class>" +
       "    <parameter>\n" +
       "        <name>p1</name>\n" +
       "        <description>Parameter 1.</description>\n" +
@@ -57,6 +58,7 @@ public class ViewConfigTest {
       "        <name>p2</name>\n" +
       "        <description>Parameter 2.</description>\n" +
       "        <required>false</required>\n" +
+      "        <masked>true</masked>" +
       "    </parameter>\n" +
       "    <resource>\n" +
       "        <name>resource</name>\n" +
@@ -145,6 +147,12 @@ public class ViewConfigTest {
   }
 
   @Test
+  public void testMasker() throws Exception {
+    ViewConfig config = getConfig();
+    Assert.assertEquals("org.apache.ambari.server.view.DefaultMasker", config.getMasker());
+  }
+
+  @Test
   public void testGetView() throws Exception {
     ViewConfig config = getConfig(view_class_xml);
     Assert.assertEquals("ViewImpl", config.getView());

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-views/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-views/pom.xml b/ambari-views/pom.xml
index e4fcb4a..23cb784 100644
--- a/ambari-views/pom.xml
+++ b/ambari-views/pom.xml
@@ -48,6 +48,10 @@
             <artifactId>jersey-core</artifactId>
             <version>1.8</version>
         </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
@@ -126,14 +130,14 @@
                         <exclude>**/*.json</exclude>
                     </excludes>
                 </configuration>
-              <executions>
-                <execution>
-                  <phase>test</phase>
-                  <goals>
-                    <goal>check</goal>
-                  </goals>
-                </execution>
-              </executions>
+                <executions>
+                    <execution>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
             </plugin>
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
@@ -152,4 +156,3 @@
     </build>
 </project>
 
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-views/src/main/java/org/apache/ambari/view/MaskException.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/MaskException.java b/ambari-views/src/main/java/org/apache/ambari/view/MaskException.java
new file mode 100644
index 0000000..b976d4a
--- /dev/null
+++ b/ambari-views/src/main/java/org/apache/ambari/view/MaskException.java
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.view;
+
+/**
+ * Indicates that a mask exception occurred.
+ */
+public class MaskException extends Exception {
+  /**
+   * Constructor.
+   *
+   * @param msg        message
+   * @param throwable  root exception
+   */
+  public MaskException(String msg, Throwable throwable) {
+    super(msg, throwable);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-views/src/main/java/org/apache/ambari/view/Masker.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/Masker.java b/ambari-views/src/main/java/org/apache/ambari/view/Masker.java
new file mode 100644
index 0000000..31d22f1
--- /dev/null
+++ b/ambari-views/src/main/java/org/apache/ambari/view/Masker.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.view;
+
+/**
+ * Masker for view parameters.
+ */
+public interface Masker {
+
+  /**
+   * Get a masked version of the given string.
+   *
+   * @param value the value to be masked
+   * @return the masked value
+   * @throws MaskException error happened during masking process
+   */
+  public String mask(String value) throws MaskException;
+
+  /**
+   * Get the original string from a masked string.
+   *
+   * @param value the value to be unmasked
+   * @return the unmasked value
+   * @throws MaskException error happened during unmasking process
+   */
+  public String unmask(String value) throws MaskException;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-views/src/main/java/org/apache/ambari/view/PersistenceException.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/PersistenceException.java b/ambari-views/src/main/java/org/apache/ambari/view/PersistenceException.java
index 6e32940..e8959b4 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/PersistenceException.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/PersistenceException.java
@@ -19,7 +19,7 @@
 package org.apache.ambari.view;
 
 /**
- * View persistence exception.  Indicates that an error occurred while
+ * View persistence exception. Indicates that an error occurred while
  * persisting a view or view data.
  */
 public class PersistenceException  extends Exception {

http://git-wip-us.apache.org/repos/asf/ambari/blob/01e9e760/ambari-views/src/main/java/org/apache/ambari/view/ViewDefinition.java
----------------------------------------------------------------------
diff --git a/ambari-views/src/main/java/org/apache/ambari/view/ViewDefinition.java b/ambari-views/src/main/java/org/apache/ambari/view/ViewDefinition.java
index 8389033..e519526 100644
--- a/ambari-views/src/main/java/org/apache/ambari/view/ViewDefinition.java
+++ b/ambari-views/src/main/java/org/apache/ambari/view/ViewDefinition.java
@@ -43,4 +43,11 @@ public interface ViewDefinition {
    * @return the version
    */
   public String getVersion();
+
+  /**
+   * Get the mask class name.
+   *
+   * @return the mask class name.
+   */
+  public String getMask();
 }