package org.jtheque.lifecycle.application; import org.jtheque.core.application.Application; import org.jtheque.core.Folders; import org.jtheque.core.utils.ImageDescriptor; import org.jtheque.core.utils.ImageType; import org.jtheque.utils.StringUtils; import org.jtheque.utils.annotations.NotThreadSafe; import org.jtheque.utils.bean.InternationalString; import org.jtheque.utils.bean.Version; import org.jtheque.utils.collections.CollectionUtils; import org.jtheque.utils.io.FileUtils; import org.jtheque.xml.utils.XML; import org.jtheque.xml.utils.XMLException; import org.jtheque.xml.utils.XMLReader; import org.w3c.dom.Node; import java.util.Collection; import java.util.Map; /* * Copyright JTheque (Baptiste Wicht) * * 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. */ /** * An XML application reader. * * @author Baptiste Wicht */ @NotThreadSafe public final class XMLApplicationReader { private XMLReader<Node> reader; /** * Read the application file. * * @param filePath The path to the application file. * * @return The builded Application. */ public Application readApplication(String filePath) { XMLApplication application = new XMLApplication(); reader = XML.newJavaFactory().newReader(); openFile(filePath); try { readFile(application); } catch (XMLException e) { throw new IllegalArgumentException("Unable to read the file " + filePath, e); } finally { FileUtils.close(reader); } return application; } /** * Open the file. * * @param filePath The path to the file. */ private void openFile(String filePath) { try { reader.openFile(filePath); } catch (XMLException e) { throw new IllegalArgumentException("Unable to read the file " + filePath, e); } } /** * Read the file. * * @param application The application to fill. * * @throws XMLException if an error occurs during the XML processing. */ private void readFile(XMLApplication application) throws XMLException { readVersion(application); readApplicationValues(application); readInternationalization(application); application.setImages(readImageDescriptor("logo"), readImageDescriptor("icon").toPath()); readOptions(application); readProperties(application); } /** * Read the version of the application from the file. * * @param application The application to fill. * * @throws XMLException if an error occurs during the XML processing. */ private void readVersion(XMLApplication application) throws XMLException { String versionStr = reader.readString("@version", reader.getRootElement()); application.setVersion(Version.get(versionStr)); } /** * Read the application values (repository, messages file) from the file. * * @param application The application to fill. * * @throws XMLException if an error occurs during the XML processing. */ private void readApplicationValues(XMLApplication application) throws XMLException { application.setProperty("application.repository", reader.readString("repository", reader.getRootElement())); application.setProperty("application.messages", reader.readString("messages", reader.getRootElement())); } /** * Read all the internationalized values of the application from the file. * * @param application The application to fill. * * @throws XMLException if an error occurs during the XML processing. */ private void readInternationalization(XMLApplication application) throws XMLException { Object i18nElement = reader.getNode("i18n", reader.getRootElement()); readLanguages(i18nElement, application); readApplicationProperties(i18nElement, application); } /** * Read all the supported languages of the application. * * @param application The application to fill. * @param i18nElement The i18n XML element. * * @throws XMLException If an errors occurs during the XML processing. */ private void readLanguages(Object i18nElement, XMLApplication application) throws XMLException { if (reader.existsNode("languages", i18nElement)) { Collection<Node> nodes = reader.getNodes("languages/*", i18nElement); Collection<String> languages = CollectionUtils.newList(nodes.size()); for (Node languageElement : nodes) { languages.add(languageElement.getNodeName()); } application.setSupportedLanguages(languages.toArray(new String[languages.size()])); } } /** * Read the application internationalisation properties. * * @param application The application to fill. * @param i18nElement The i18n XML element. * * @throws XMLException If an errors occurs during the XML processing. */ private void readApplicationProperties(Object i18nElement, XMLApplication application) throws XMLException { if (reader.getNode("files", i18nElement) != null || reader.getNode("name", i18nElement) == null) { application.setApplicationProperties(new I18nApplicationProperties()); } else { application.setApplicationProperties(new DirectValuesApplicationProperties( readInternationalString("author", i18nElement), readInternationalString("name", i18nElement), readInternationalString("site", i18nElement), readInternationalString("email", i18nElement), readInternationalString("copyright", i18nElement) )); } } /** * Read an international string from the file. * * @param path The path the international string element. * @param parentElement The parent element. * * @return The internationalized string. * * @throws XMLException if an error occurs during the XML processing. */ private InternationalString readInternationalString(String path, Object parentElement) throws XMLException { Collection<Node> elements = reader.getNodes(path + "/*", parentElement); Map<String, String> resources = CollectionUtils.newHashMap(5); for (Node child : elements) { resources.put(child.getNodeName(), child.getTextContent()); } return new InternationalString(resources); } /** * Read the window icon information from the file. * * @param node The node to read the image from. * * @return Return the read image descriptor. If the node doesn't exists a default ImageDescriptor with the name of * the node as the image and PNG type is returned. * * @throws XMLException if an error occurs during the XML processing. */ private ImageDescriptor readImageDescriptor(String node) throws XMLException { if (reader.existsNode(node, reader.getRootElement())) { Object iconElement = reader.getNode(node, reader.getRootElement()); StringBuilder path = new StringBuilder(Folders.getApplicationFolder().getAbsolutePath()); path.append("/images/"); path.append(reader.readString("@image", iconElement)); String typeStr = reader.readString("@type", iconElement); if(StringUtils.isEmpty(typeStr)){ typeStr = "png"; } return new ImageDescriptor(path.toString(), ImageType.resolve(typeStr)); } return new ImageDescriptor(node, ImageType.PNG); } /** * Read the application options from the file. * * @param application The application to fill. * * @throws XMLException if an error occurs during the XML processing. */ private void readOptions(XMLApplication application) throws XMLException { if (reader.existsNode("options", reader.getRootElement())) { Object element = reader.getNode("options", reader.getRootElement()); if (exists("license", element)) { application.displayLicense(); application.setProperty("application.license", Folders.getApplicationFolder().getAbsolutePath() + reader.readString("license", element)); } readOption(application, element, "concurrent.load"); readOption(application, element, "concurrent.start"); readProperty(application, element, "url.bugs"); readProperty(application, element, "url.improvement"); readProperty(application, element, "url.help"); } } /** * Read the option from the application. * * @param application the application. * @param element The current element. * @param option The option to read. * * @throws XMLException if an error occurs during the XML processing. */ private void readOption(XMLApplication application, Object element, String option) throws XMLException { if (exists(option, element)) { application.setProperty(option, reader.readString(option, element)); System.setProperty("jtheque." + option, reader.readString(option, element)); } } /** * Read the property from the application. * * @param application the application. * @param element The current element. * @param property The property to read. * * @throws XMLException if an error occurs during the XML processing. */ private void readProperty(XMLApplication application, Object element, String property) throws XMLException { if (exists(property, element)) { application.setProperty(property, reader.readString(property, element)); } else { application.setProperty(property, ""); } } /** * Indicate if the value exists or not. * * @param request The XPath request. * @param element The current element. * * @return {@code true} if the value exists or not. * * @throws XMLException if an error occurs during the XML processing. */ private boolean exists(String request, Object element) throws XMLException { return reader.existsValue(request, element) && StringUtils.isNotEmpty(reader.readString(request, element)); } /** * Read the application properties from the file. * * @param application The application to fill. * * @throws XMLException if an error occurs during the XML processing. */ private void readProperties(XMLApplication application) throws XMLException { Collection<Node> nodes = reader.getNodes("properties/*", reader.getRootElement()); for (Node propertyElement : nodes) { application.setProperty(propertyElement.getNodeName(), propertyElement.getTextContent()); } } }