Repository: ambari
Updated Branches:
  refs/heads/trunk af0253506 -> 2bebb6e1e


AMBARI-7964 - Views: on deploy, validate view.xml


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

Branch: refs/heads/trunk
Commit: 2bebb6e1e3e7a0570996f2c4b458289f6763feda
Parents: af02535
Author: tbeerbower <[email protected]>
Authored: Mon Oct 27 10:08:35 2014 -0400
Committer: tbeerbower <[email protected]>
Committed: Mon Oct 27 10:09:05 2014 -0400

----------------------------------------------------------------------
 .../server/configuration/Configuration.java     | 19 +++-
 .../ambari/server/view/ViewArchiveUtility.java  | 46 ++++++++--
 .../apache/ambari/server/view/ViewRegistry.java |  3 +-
 .../server/configuration/ConfigurationTest.java | 15 ++++
 .../server/view/ViewArchiveUtilityTest.java     | 38 ++++++++
 .../ambari/server/view/ViewExtractorTest.java   |  3 +-
 .../ambari/server/view/ViewRegistryTest.java    |  3 +-
 ambari-server/src/test/resources/test_view.xml  | 94 ++++++++++++++++++++
 8 files changed, 209 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
index feb4318..ed59e8a 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
@@ -61,6 +61,8 @@ public class Configuration {
   public static final String BOOTSTRAP_DIR_DEFAULT = 
"/var/run/ambari-server/bootstrap";
   public static final String VIEWS_DIR = "views.dir";
   public static final String VIEWS_DIR_DEFAULT = 
"/var/lib/ambari-server/resources/views";
+  public static final String VIEWS_VALIDATE = "views.validate";
+  public static final String VIEWS_VALIDATE_DEFAULT = "false";
   public static final String WEBAPP_DIR = "webapp.dir";
   public static final String BOOTSTRAP_SCRIPT = "bootstrap.script";
   public static final String BOOTSTRAP_SCRIPT_DEFAULT = 
"/usr/bin/ambari_bootstrap";
@@ -529,6 +531,15 @@ public class Configuration {
     return new File(fileName);
   }
 
+  /**
+   * Determine whether or not view validation is enabled.
+   *
+   * @return true if view validation is enabled
+   */
+  public boolean isViewValidationEnabled() {
+    return "true".equalsIgnoreCase(properties.getProperty(VIEWS_VALIDATE, 
VIEWS_VALIDATE_DEFAULT));
+  }
+
   public File getBootStrapDir() {
     String fileName = properties.getProperty(BOOTSTRAP_DIR, 
BOOTSTRAP_DIR_DEFAULT);
     return new File(fileName);
@@ -616,7 +627,7 @@ public class Configuration {
    * @return null if such a file is not present, value if present.
    */
   public String getHostsMapFile() {
-    LOG.info("Hosts Mapping File " +  
properties.getProperty(SRVR_HOSTS_MAPPING));
+    LOG.info("Hosts Mapping File " + 
properties.getProperty(SRVR_HOSTS_MAPPING));
     return properties.getProperty(SRVR_HOSTS_MAPPING);
   }
 
@@ -1015,12 +1026,12 @@ public class Configuration {
 
   public String getExecutionSchedulerThreads() {
     return properties.getProperty(EXECUTION_SCHEDULER_THREADS,
-      DEFAULT_SCHEDULER_THREAD_COUNT);
+        DEFAULT_SCHEDULER_THREAD_COUNT);
   }
 
   public String getExecutionSchedulerConnections() {
     return properties.getProperty(EXECUTION_SCHEDULER_CONNECTIONS,
-      DEFAULT_SCHEDULER_MAX_CONNECTIONS);
+        DEFAULT_SCHEDULER_MAX_CONNECTIONS);
   }
 
   public Long getExecutionSchedulerMisfireToleration() {
@@ -1032,7 +1043,7 @@ public class Configuration {
 
   public Integer getExecutionSchedulerStartDelay() {
     String delay = properties.getProperty(EXECUTION_SCHEDULER_START_DELAY,
-      DEFAULT_SCHEDULER_START_DELAY_SECONDS);
+        DEFAULT_SCHEDULER_START_DELAY_SECONDS);
     return Integer.parseInt(delay);
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java
index f5f2732..950f552 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/view/ViewArchiveUtility.java
@@ -19,10 +19,15 @@
 package org.apache.ambari.server.view;
 
 import org.apache.ambari.server.view.configuration.ViewConfig;
+import org.xml.sax.SAXException;
 
+import javax.xml.XMLConstants;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -43,6 +48,7 @@ public class ViewArchiveUtility {
    * Constants
    */
   private static final String VIEW_XML = "view.xml";
+  private static final String VIEW_XSD = "view.xsd";
 
 
   // ----- ViewArchiveUtility ------------------------------------------------
@@ -53,6 +59,8 @@ public class ViewArchiveUtility {
    * @param archiveFile  the archive file
    *
    * @return the associated view configuration
+   *
+   * @throws JAXBException if xml is malformed
    */
   public ViewConfig getViewConfigFromArchive(File archiveFile)
       throws MalformedURLException, JAXBException {
@@ -68,17 +76,25 @@ public class ViewArchiveUtility {
   /**
    * Get the view configuration from the extracted archive file.
    *
-   * @param archivePath path to extracted archive
+   * @param archivePath  path to extracted archive
+   * @param validate     indicates whether or not the view configuration 
should be validated
    *
    * @return the associated view configuration
    *
    * @throws JAXBException if xml is malformed
-   * @throws java.io.FileNotFoundException if xml was not found
+   * @throws IOException if xml can not be read
+   * @throws SAXException if the validation fails
    */
-  public ViewConfig getViewConfigFromExtractedArchive(String archivePath)
-      throws JAXBException, FileNotFoundException {
+  public ViewConfig getViewConfigFromExtractedArchive(String archivePath, 
boolean validate)
+      throws JAXBException, IOException, SAXException {
+
+    File configFile = new File(archivePath + File.separator + VIEW_XML);
+
+    if (validate) {
+      validateConfig(new FileInputStream(configFile));
+    }
 
-    InputStream configStream      = new FileInputStream(new File(archivePath + 
File.separator + VIEW_XML));
+    InputStream  configStream     = new FileInputStream(configFile);
     JAXBContext  jaxbContext      = JAXBContext.newInstance(ViewConfig.class);
     Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
 
@@ -117,4 +133,24 @@ public class ViewArchiveUtility {
   public JarFile getJarFile(File file) throws IOException {
     return new JarFile(file);
   }
+
+
+  // ----- helper methods ----------------------------------------------------
+
+  /**
+   * Validate the given view descriptor file against the view schema.
+   *
+   * @param configStream  input stream of view descriptor file to be validated
+   *
+   * @throws SAXException if the validation fails
+   * @throws IOException if the descriptor file can not be read
+   */
+  protected void validateConfig(InputStream  configStream) throws 
SAXException, IOException {
+    SchemaFactory schemaFactory = 
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+
+    URL schemaUrl = getClass().getClassLoader().getResource(VIEW_XSD);
+    Schema schema = schemaFactory.newSchema(schemaUrl);
+
+    schema.newValidator().validate(new StreamSource(configStream));
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/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 c4da8b4..a5d11bd 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
@@ -1290,7 +1290,8 @@ public class ViewRegistry {
       // extract the archive and get the class loader
       ClassLoader cl = extractor.extractViewArchive(viewDefinition, 
archiveFile, extractedArchiveDirFile);
 
-      ViewConfig viewConfig = 
archiveUtility.getViewConfigFromExtractedArchive(extractedArchiveDirPath);
+      ViewConfig viewConfig = 
archiveUtility.getViewConfigFromExtractedArchive(extractedArchiveDirPath,
+          configuration.isViewValidationEnabled());
 
       setupViewDefinition(viewDefinition, viewConfig, cl);
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
index 12b5333..0f7de36 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/configuration/ConfigurationTest.java
@@ -305,6 +305,21 @@ public class ConfigurationTest {
   }
 
   @Test
+  public void testIsViewValidationEnabled() throws Exception {
+    final Properties ambariProperties = new Properties();
+    Configuration configuration = new Configuration(ambariProperties);
+    Assert.assertFalse(configuration.isViewValidationEnabled());
+
+    ambariProperties.setProperty(Configuration.VIEWS_VALIDATE, "false");
+    configuration = new Configuration(ambariProperties);
+    Assert.assertFalse(configuration.isViewValidationEnabled());
+
+    ambariProperties.setProperty(Configuration.VIEWS_VALIDATE, "true");
+    configuration = new Configuration(ambariProperties);
+    Assert.assertTrue(configuration.isViewValidationEnabled());
+  }
+
+  @Test
   public void testGetLdapServerProperties() throws Exception {
     final Properties ambariProperties = new Properties();
     final Configuration configuration = new Configuration(ambariProperties);

http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/java/org/apache/ambari/server/view/ViewArchiveUtilityTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewArchiveUtilityTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewArchiveUtilityTest.java
new file mode 100644
index 0000000..aff29f4
--- /dev/null
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewArchiveUtilityTest.java
@@ -0,0 +1,38 @@
+/**
+ * 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 org.junit.Test;
+
+import java.io.InputStream;
+
+/**
+ * ViewArchiveUtility tests.
+ */
+public class ViewArchiveUtilityTest {
+
+  @Test
+  public void testValidateConfig() throws Exception {
+    ViewArchiveUtility utility = new ViewArchiveUtility();
+
+    InputStream configStream = 
getClass().getClassLoader().getResourceAsStream("test_view.xml");
+
+    utility.validateConfig(configStream);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java
index 1b71c37..b66714e 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewExtractorTest.java
@@ -234,7 +234,8 @@ public class ViewExtractorTest {
       return viewConfigs.get(archiveFile);
     }
 
-    public ViewConfig getViewConfigFromExtractedArchive(String archivePath)
+    @Override
+    public ViewConfig getViewConfigFromExtractedArchive(String archivePath, 
boolean validate)
         throws JAXBException, FileNotFoundException {
       for (File viewConfigKey: viewConfigs.keySet()) {
         if (viewConfigKey.getAbsolutePath().equals(archivePath)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
 
b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
index 7c0cade..1d98b6c 100644
--- 
a/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
+++ 
b/ambari-server/src/test/java/org/apache/ambari/server/view/ViewRegistryTest.java
@@ -1111,7 +1111,8 @@ public class ViewRegistryTest {
       return viewConfigs.get(archiveFile);
     }
 
-    public ViewConfig getViewConfigFromExtractedArchive(String archivePath)
+    @Override
+    public ViewConfig getViewConfigFromExtractedArchive(String archivePath, 
boolean validate)
         throws JAXBException, FileNotFoundException {
       for (File viewConfigKey: viewConfigs.keySet()) {
         if (viewConfigKey.getAbsolutePath().equals(archivePath)) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/2bebb6e1/ambari-server/src/test/resources/test_view.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/resources/test_view.xml 
b/ambari-server/src/test/resources/test_view.xml
new file mode 100644
index 0000000..5742bfe
--- /dev/null
+++ b/ambari-server/src/test/resources/test_view.xml
@@ -0,0 +1,94 @@
+<!--
+   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.
+-->
+<view>
+  <name>view1</name>
+  <label>str1234</label>
+  <version>str1234</version>
+  <description>str1234</description>
+  <icon64>str1234</icon64>
+  <icon>str1234</icon>
+  <system>true</system>
+  <view-class>str1234</view-class>
+  <masker-class>str1234</masker-class>
+  <parameter>
+    <name>parameter1</name>
+    <description>str1234</description>
+    <required>true</required>
+    <masked>true</masked>
+  </parameter>
+  <parameter>
+    <name>parameter2</name>
+    <description>str1234</description>
+    <required>false</required>
+    <masked>false</masked>
+  </parameter>
+  <resource>
+    <name>resource1</name>
+    <plural-name>str1234</plural-name>
+    <id-property>str1234</id-property>
+    <resource-class>str1234</resource-class>
+    <provider-class>str1234</provider-class>
+    <service-class>str1234</service-class>
+    <sub-resource-name>resource2</sub-resource-name>
+  </resource>
+  <resource>
+    <name>resource2</name>
+    <plural-name>str1234</plural-name>
+    <id-property>str1234</id-property>
+    <resource-class>str1234</resource-class>
+    <provider-class>str1234</provider-class>
+    <service-class>str1234</service-class>
+  </resource>
+  <resource>
+    <name>resource3</name>
+    <service-class>str1234</service-class>
+  </resource>
+  <permission>
+    <name>permission1</name>
+    <description>str1234</description>
+  </permission>
+  <permission>
+    <name>permission2</name>
+    <description>str1234</description>
+  </permission>
+  <persistence>
+    <entity>
+      <class>entity1</class>
+      <id-property>str1234</id-property>
+    </entity>
+    <entity>
+      <class>entity2</class>
+      <id-property>str1234</id-property>
+    </entity>
+  </persistence>
+  <instance>
+    <name>instance1</name>
+    <label>str1234</label>
+    <description>str1234</description>
+    <icon64>str1234</icon64>
+    <icon>str1234</icon>
+    <visible>true</visible>
+    <property>
+      <key>parameter1</key>
+      <value>str1234</value>
+    </property>
+    <property>
+      <key>parameter2</key>
+      <value>str1234</value>
+    </property>
+  </instance>
+</view>

Reply via email to