/* * Copyright 2008-2014 the original author or authors * * Licensed 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.kaleidofoundry.core.config; import static org.kaleidofoundry.core.config.ConfigurationConstants.KeyRoot; import static org.kaleidofoundry.core.config.ConfigurationConstants.KeySeparator; import java.io.IOException; import java.io.Serializable; import java.io.StringWriter; import java.io.Writer; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.StringTokenizer; import java.util.TimeZone; import org.kaleidofoundry.core.cache.Cache; import org.kaleidofoundry.core.context.RuntimeContext; import org.kaleidofoundry.core.plugin.Declare; import org.kaleidofoundry.core.store.ResourceException; import org.kaleidofoundry.core.store.ResourceHandler; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions.FlowStyle; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.representer.Representer; /** * Yaml configuration implementation * * @author jraduget */ @Declare(ConfigurationConstants.YamlConfigurationPluginName) public class YamlConfiguration extends AbstractConfiguration { public YamlConfiguration(final RuntimeContext<Configuration> context) throws ResourceException { super(context); } public YamlConfiguration(final String name, final String resourceUri, final RuntimeContext<Configuration> context) throws ResourceException { super(name, resourceUri, context); } /* * (non-Javadoc) * @see org.kaleidofoundry.core.config.AbstractConfiguration#loadProperties(org.kaleidofoundry.core.store.ResourceHandler, * org.kaleidofoundry.core.cache.Cache) */ @Override protected Cache<String, Serializable> loadProperties(final ResourceHandler resourceHandler, final Cache<String, Serializable> properties) throws ResourceException, ConfigurationException { // log timezone information for date value LOGGER.debug("java default timezone is {}", TimeZone.getDefault()); // loader options Representer option = new Representer(); // this avoid a time offset, due to the default system timezone (api it seems to not work) // option.setTimeZone(TimeZone.getTimeZone("GMT")); Yaml yaml = new Yaml(option); // load all yaml documents ( --- ...) Iterable<Object> objectList = yaml.loadAll(resourceHandler.getReader()); // for each document of the resource, load it for (Object obj : objectList) { feedProperties(obj, new StringBuilder(), properties); } return properties; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.config.AbstractConfiguration#storeProperties(org.kaleidofoundry.core.store.ResourceHandler, * org.kaleidofoundry.core.cache.Cache) */ @Override protected Cache<String, Serializable> storeProperties(final ResourceHandler resourceHandler, final Cache<String, Serializable> cacheProperties) throws ResourceException, ConfigurationException { DumperOptions options = new DumperOptions(); options.setPrettyFlow(true); options.setDefaultFlowStyle(FlowStyle.BLOCK); // this avoid a time offset, due to the default system timezone (api it seems to not work) // options.setTimeZone(TimeZone.getTimeZone("GMT")); final Yaml yaml = new Yaml(options); final Map<String, Object> rootYamlMap = new LinkedHashMap<String, Object>(); final Map<String, Map<String, Object>> registeredMap = new HashMap<String, Map<String, Object>>(); for (String key : keySet()) { StringTokenizer strToken = new StringTokenizer(key.substring(KeyRoot.length()), KeySeparator); String subKey = ""; Map<String, Object> currentYamlMap = rootYamlMap; while (strToken.hasMoreTokens()) { String nodeName = strToken.nextToken(); subKey = subKey + KeySeparator + nodeName; Map<String, Object> newYamlMap; if (!registeredMap.containsKey(subKey)) { newYamlMap = new LinkedHashMap<String, Object>(); registeredMap.put(subKey, newYamlMap); } else { newYamlMap = registeredMap.get(subKey); } if (strToken.hasMoreElements()) { currentYamlMap.put(nodeName, newYamlMap); currentYamlMap = newYamlMap; } else { currentYamlMap.put(nodeName, getProperty(key)); /* * List<String> values = getStringList(key); * if (values == null || values.size() == 1) { * currentYamlMap.put(nodeName, getProperty(key)); * } else { * currentYamlMap.put(nodeName, values); * } */ currentYamlMap = newYamlMap; } } } Writer yamlWriter = null; try { // create output writer yamlWriter = new StringWriter(); // write yaml content yaml.dump(rootYamlMap, yamlWriter); // Store the document content singleFileStore.store(singleFileStore.createResourceHandler(resourceHandler.getUri(), yamlWriter.toString())); return cacheProperties; } catch (IOException ioe) { if (ioe instanceof ResourceException) { throw (ResourceException) ioe; } else { throw new ResourceException(ioe, resourceHandler.getUri()); } } finally { if (yamlWriter != null) { try { yamlWriter.close(); } catch (IOException ioe) { throw new ResourceException(ioe, resourceHandler.getUri()); } } } } /** * recursive method, use to * * @param nodeList * @param keyName * @param cacheProperties */ @SuppressWarnings("unchecked") protected <T extends Serializable> void feedProperties(final Object values, final StringBuilder keyName, final Cache<String, Serializable> cacheProperties) { if (values instanceof Map) { Map<String, ?> valuesByName = Map.class.cast(values); for (Entry<String, ?> node : valuesByName.entrySet()) { final StringBuilder newKeyName = new StringBuilder(keyName).append(keyName.length() > 0 ? KeySeparator : KeyRoot).append(node.getKey()); feedProperties(node.getValue(), newKeyName, cacheProperties); } } else if (values instanceof Collection) { cacheProperties.put(keyName.toString(), (Serializable) values); /* * Collection<?> result = Collection.class.cast(values); * List<String> serializedValues = new LinkedList<String>(); * int cpt = 0; * for (Object o : result) { * T value = (T) o; * Class<T> c = (Class<T>) o.getClass(); * LOGGER.debug("{}[{}] : {value='{}', class='{}' serialization='{}'}", new String[] { keyName.toString(), String.valueOf(cpt), * String.valueOf(value), * value.getClass().getName(), serialize(value, c) }); * serializedValues.add(serialize(value, c)); * cpt++; * } * // properties.put(keyName.toString(), StringHelper.unsplit(MultiValuesSeparator, serializedValues.toArray(new * // Object[serializedValues.size()]))); * cacheProperties.put(keyName.toString(), (Serializable) serializedValues); */ } else { if (values != null) { T value = (T) values; Class<T> c = (Class<T>) values.getClass(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("{} : {value='{}', class='{}' serialization='{}'}", new String[] { keyName.toString(), String.valueOf(value), value.getClass().getName(), serialize(value, c) }); } // properties.put(keyName.toString(), serialize(value, c)); cacheProperties.put(keyName.toString(), value); } else { cacheProperties.put(keyName.toString(), ""); } } } }