001 /*
002 * SPDX-License-Identifier: Apache-2.0
003 *
004 * Copyright 2008-2017 the original author or authors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.codehaus.griffon.runtime.util;
019
020 import griffon.core.resources.ResourceHandler;
021 import griffon.util.AbstractMapResourceBundle;
022 import griffon.util.ResourceBundleReader;
023 import org.w3c.dom.Document;
024 import org.w3c.dom.Node;
025 import org.w3c.dom.NodeList;
026
027 import javax.annotation.Nonnull;
028 import javax.inject.Inject;
029 import javax.inject.Named;
030 import javax.xml.parsers.DocumentBuilder;
031 import javax.xml.parsers.DocumentBuilderFactory;
032 import javax.xml.parsers.ParserConfigurationException;
033 import java.net.URL;
034 import java.util.ArrayList;
035 import java.util.Collection;
036 import java.util.LinkedHashMap;
037 import java.util.List;
038 import java.util.Map;
039 import java.util.ResourceBundle;
040
041 import static griffon.util.GriffonNameUtils.requireNonBlank;
042 import static java.util.Objects.requireNonNull;
043
044 /**
045 * @author Andres Almiray
046 * @since 2.11.0
047 */
048 @Named("xml")
049 public class XmlResourceBundleLoader extends AbstractResourceBundleLoader {
050 protected static final String XML_SUFFIX = ".xml";
051
052 protected final ResourceBundleReader resourceBundleReader;
053
054 @Inject
055 public XmlResourceBundleLoader(@Nonnull ResourceHandler resourceHandler,
056 @Nonnull ResourceBundleReader resourceBundleReader) {
057 super(resourceHandler);
058 this.resourceBundleReader = requireNonNull(resourceBundleReader, "Argument 'resourceBundleReader' must not be null");
059 }
060
061 @Nonnull
062 @Override
063 public Collection<ResourceBundle> load(@Nonnull String name) {
064 requireNonBlank(name, ERROR_FILENAME_BLANK);
065 List<ResourceBundle> bundles = new ArrayList<>();
066 List<URL> resources = getResources(name, XML_SUFFIX);
067
068 if (resources != null) {
069 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
070 DocumentBuilder documentBuilder = null;
071
072 try {
073 documentBuilder = documentBuilderFactory.newDocumentBuilder();
074 } catch (ParserConfigurationException e) {
075 throw new IllegalStateException("Can not read " + name + XML_SUFFIX, e);
076 }
077
078 for (URL resource : resources) {
079 if (null == resource) { continue; }
080 try {
081 Document document = documentBuilder.parse(resource.openStream());
082 ResourceBundle bundle = resourceBundleReader.read(toResourceBundle(document));
083 bundles.add(bundle);
084 } catch (Exception e) {
085 // ignore
086 }
087 }
088 }
089
090 return bundles;
091 }
092
093 @Nonnull
094 private ResourceBundle toResourceBundle(@Nonnull Document document) {
095 document.getDocumentElement().normalize();
096
097 final Map<String, Object> map = new LinkedHashMap<>();
098 traverseNodes(map, document.getDocumentElement().getChildNodes());
099
100 return new AbstractMapResourceBundle() {
101 @Override
102 protected void initialize(@Nonnull Map<String, Object> entries) {
103 entries.putAll(map);
104 }
105 };
106 }
107
108 private void traverseNodes(@Nonnull Map<String, Object> accumulator, @Nonnull NodeList nodes) {
109 for (int index = 0; index < nodes.getLength(); index++) {
110 Node item = nodes.item(index);
111 if (item.getNodeType() != Node.ELEMENT_NODE) {
112 continue;
113 }
114
115 String key = item.getNodeName();
116 if (item.hasChildNodes()) {
117 if (item.getChildNodes().getLength() == 1) {
118 accumulator.put(key, item.getTextContent().trim());
119 } else {
120 Map<String, Object> map = new LinkedHashMap<>();
121 traverseNodes(map, item.getChildNodes());
122 accumulator.put(key, map);
123 }
124 } else {
125 accumulator.put(key, "");
126 }
127 }
128 }
129 }
|