001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.configuration2; 019 020import org.apache.commons.configuration2.ex.ConfigurationException; 021import org.apache.commons.configuration2.ex.ConfigurationRuntimeException; 022import org.apache.commons.configuration2.io.InputStreamSupport; 023import org.apache.commons.configuration2.tree.ImmutableNode; 024import org.yaml.snakeyaml.DumperOptions; 025import org.yaml.snakeyaml.LoaderOptions; 026import org.yaml.snakeyaml.Yaml; 027import org.yaml.snakeyaml.constructor.Constructor; 028import org.yaml.snakeyaml.representer.Representer; 029 030import java.io.IOException; 031import java.io.InputStream; 032import java.io.Reader; 033import java.io.Writer; 034import java.util.Map; 035 036/** 037 * <p> 038 * A specialized hierarchical configuration class that is able to parse YAML 039 * documents. 040 * </p> 041 * 042 * @since 2.2 043 */ 044public class YAMLConfiguration extends AbstractYAMLBasedConfiguration 045 implements FileBasedConfiguration, InputStreamSupport 046{ 047 /** 048 * Creates a new instance of {@code YAMLConfiguration}. 049 */ 050 public YAMLConfiguration() 051 { 052 super(); 053 } 054 055 /** 056 * Creates a new instance of {@code YAMLConfiguration} as a copy of the 057 * specified configuration. 058 * 059 * @param c the configuration to be copied 060 */ 061 public YAMLConfiguration(final HierarchicalConfiguration<ImmutableNode> c) 062 { 063 super(c); 064 } 065 066 @Override 067 public void read(final Reader in) throws ConfigurationException 068 { 069 try 070 { 071 final Yaml yaml = createYamlForReading(new LoaderOptions()); 072 final Map<String, Object> map = (Map) yaml.load(in); 073 load(map); 074 } 075 catch (final Exception e) 076 { 077 rethrowException(e); 078 } 079 } 080 081 public void read(final Reader in, final LoaderOptions options) 082 throws ConfigurationException 083 { 084 try 085 { 086 final Yaml yaml = createYamlForReading(options); 087 final Map<String, Object> map = (Map) yaml.load(in); 088 load(map); 089 } 090 catch (final Exception e) 091 { 092 rethrowException(e); 093 } 094 } 095 096 @Override 097 public void write(final Writer out) throws ConfigurationException, IOException 098 { 099 final DumperOptions options = new DumperOptions(); 100 options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); 101 dump(out, options); 102 } 103 104 public void dump(final Writer out, final DumperOptions options) 105 throws ConfigurationException, IOException 106 { 107 final Yaml yaml = new Yaml(options); 108 yaml.dump(constructMap(getNodeModel().getNodeHandler().getRootNode()), 109 out); 110 } 111 112 /** 113 * Loads the configuration from the given input stream. 114 * 115 * @param in the input stream 116 * @throws ConfigurationException if an error occurs 117 */ 118 @Override 119 public void read(final InputStream in) throws ConfigurationException 120 { 121 try 122 { 123 final Yaml yaml = createYamlForReading(new LoaderOptions()); 124 final Map<String, Object> map = (Map) yaml.load(in); 125 load(map); 126 } 127 catch (final Exception e) 128 { 129 rethrowException(e); 130 } 131 } 132 133 public void read(final InputStream in, final LoaderOptions options) 134 throws ConfigurationException 135 { 136 try 137 { 138 final Yaml yaml = createYamlForReading(options); 139 final Map<String, Object> map = (Map) yaml.load(in); 140 load(map); 141 } 142 catch (final Exception e) 143 { 144 rethrowException(e); 145 } 146 } 147 148 /** 149 * Creates a {@code Yaml} object for reading a Yaml file. The object is 150 * configured with some default settings. 151 * 152 * @param options options for loading the file 153 * @return the {@code Yaml} instance for loading a file 154 */ 155 private static Yaml createYamlForReading(LoaderOptions options) 156 { 157 return new Yaml(createClassLoadingDisablingConstructor(), new Representer(), new DumperOptions(), options); 158 } 159 160 /** 161 * Returns a {@code Constructor} object for the YAML parser that prevents 162 * all classes from being loaded. This effectively disables the dynamic 163 * creation of Java objects that are declared in YAML files to be loaded. 164 * 165 * @return the {@code Constructor} preventing object creation 166 */ 167 private static Constructor createClassLoadingDisablingConstructor() 168 { 169 return new Constructor() 170 { 171 @Override 172 protected Class<?> getClassForName(String name) 173 { 174 throw new ConfigurationRuntimeException("Class instantiation is disabled."); 175 } 176 }; 177 } 178}