Java tutorial
/* * #%L * settings4j * =============================================================== * Copyright (C) 2008 - 2016 Brabenetz Harald, Austria * =============================================================== * 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. * #L% */ package org.settings4j.connector; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.settings4j.contentresolver.ClasspathContentResolver; import org.settings4j.contentresolver.FSContentResolver; /** * The {@link Properties}-File implementation of an {@link org.settings4j.Connector}. * <h3>1. Example - Use Property-File from Classpath or Filepath</h3> * <p> * Example usage read property File from Classpath or Filepath: <br> * In this case a prefix "file:" or "classpath:" is required. * </p> * * <pre> * <settings4j:configuration xmlns:settings4j='http://settings4j.org/'> * * <connector name="PropertyFileConnector" class="org.settings4j.connector.PropertyFileConnector"> * <param name="propertyFromPath" value="classpath:org/settings4j/config/propertyFile.properties" /> * </connector> * * </settings4j:configuration> * </pre> * * <h3>2. Example - get the path to the Property File from any other Connector</h3> * <p> * In this Example you can configure the path to your Property-File via System-Properties or per Server-JNDI-Context.<br> * E.g.: Start your application with: "-DmyAppConfig=file:/somePath/myConfig.properties" * </p> * * <pre> * <settings4j:configuration xmlns:settings4j='http://settings4j.org/'> * * <connector name="PropertyFileConnector" class="org.settings4j.connector.PropertyFileConnector"> * <param name="propertyFromPath" value="${connectors.string['myAppConfig']}" /> * <connector-ref ref="SystemPropertyConnector" /> * <connector-ref ref="JNDIConnector" /> * </connector> * * <connector name="SystemPropertyConnector" class="org.settings4j.connector.SystemPropertyConnector"/> * * <connector name="JNDIConnector" class="org.settings4j.connector.JNDIConnector"/> * * </settings4j:configuration> * </pre> * * <h3>3. Resolve relative Paths in your Property File</h3> * <p> * In many application it is required to configure some paths.<br> * Some Examples are: * </p> * <ul> * <li>path to your message-Properties * <li>path to other configuration-Files (e.g.: log4j.xml) * <li>path to some folders (file-upload, cache-directory, log-directory) * <li>other paths * </ul> * <p> * The chance are good, that you want place this folders somewhere relative to the property file.<br> * You must only set the parameter "resolveRelativePaths" on the PropertyFileConnector to "true", and all values from the Property-File which starts with * "file:." will be resolved relative to the Property-File. * </p> * * <pre> * <settings4j:configuration xmlns:settings4j='http://settings4j.org/'> * * <connector name="SystemPropertyConnector" class="org.settings4j.connector.SystemPropertyConnector"/> * * <connector name="PropertyFileConnector" class="org.settings4j.connector.PropertyFileConnector"> * <param name="propertyFromPath" value="${connectors.string['myAppConfig']}" /> * <param name="resolveRelativePaths" value="true /> * <connector-ref ref="SystemPropertyConnector" /> * </connector> * * </settings4j:configuration> * </pre> * <p> * With this config, you can start your app with <code>"-DmyAppConfig=file:/somePath/myConfig.properties"</code>.<br> * In "myConfig.properties" you have somewhere configured the property:<br> * <code>xyz=file:./test.xml</code><br> * The Settings4j.getString("xyz") will return the {@link URL}-Qualified path: "file:/somePath/test.xml" * </p> * * @author Harald.Brabenetz */ public class PropertyFileConnector extends AbstractPropertyConnector { private Properties property = new Properties(); private boolean resolveRelativePaths; private URL propertyFileFolderUrl; @Override public String getString(final String key) { return this.property.getProperty(key, null); } public void setProperty(final Properties property) { this.property = property; } // SuppressWarnings PMD.DefaultPackage: used for UnitTests validation. @SuppressWarnings("PMD.DefaultPackage") URL getPropertyFileFolderUrl() { return this.propertyFileFolderUrl; } /** * @param resolveRelativePaths * set to true if Property Values wit a relative path (starting with "file:.") should be replace with a full qualified URL Path relative to the * Property-File */ public void setResolveRelativePaths(final boolean resolveRelativePaths) { this.resolveRelativePaths = resolveRelativePaths; resolveRelativePaths(); } private void setPropertyFromContentInternal(final byte[] content, final String propertyPath) { Validate.notNull(content, "No Property-File found for path: '%s'", propertyPath); final Properties tmpProperty = new Properties(); try { tmpProperty.load(new ByteArrayInputStream(content)); this.property = tmpProperty; } catch (final IOException e) { throw new IllegalArgumentException(e); } } /** * @param propertyPath * The filepath to a Property-File. Supported prefixes: "file:" and "classpath:". */ public void setPropertyFromPath(final String propertyPath) { if (StringUtils.isEmpty(propertyPath)) { throw new IllegalArgumentException("The Property Path cannot be empty"); } if (propertyPath.startsWith(FSContentResolver.FILE_URL_PREFIX)) { final byte[] content = new FSContentResolver().getContent(propertyPath); setPropertyFromContentInternal(content, propertyPath); this.propertyFileFolderUrl = getParentFolderUrlFromFile(propertyPath); } else if (propertyPath.startsWith(ClasspathContentResolver.CLASSPATH_URL_PREFIX)) { final byte[] content = new ClasspathContentResolver().getContent(propertyPath); setPropertyFromContentInternal(content, propertyPath); this.propertyFileFolderUrl = getParentFolderUrlFromClasspath(propertyPath); } else { throw new IllegalArgumentException("The Property Path must start with 'file:' or 'classpath:'. " // + "But the File Property Path was: '" + propertyPath + "'."); } resolveRelativePaths(); } private static URL getParentFolderUrlFromClasspath(final String propertyPath) { final URL resource = ClasspathContentResolver.getResource(propertyPath); Validate.notNull(resource, "The URL for '%s' was null", propertyPath); final String fullPathNoEndSeparator = FilenameUtils.getFullPathNoEndSeparator(resource.toExternalForm()); return createURL(fullPathNoEndSeparator + "/"); } private static URL getParentFolderUrlFromFile(final String propertyPath) { final File propertyFile = new File( StringUtils.removeStart(propertyPath, FSContentResolver.FILE_URL_PREFIX)); try { return propertyFile.getParentFile().toURI().toURL(); } catch (final IOException e) { throw new IllegalArgumentException(e); } } private void resolveRelativePaths() { if (!this.resolveRelativePaths) { return; } if (this.propertyFileFolderUrl == null) { return; } final Set<Entry<Object, Object>> entrySet = this.property.entrySet(); for (final Entry<Object, Object> entry : entrySet) { final String propValue = entry.getValue().toString(); if (propValue.startsWith(FSContentResolver.FILE_URL_PREFIX + ".")) { final String valuePath = StringUtils.removeStart(propValue, FSContentResolver.FILE_URL_PREFIX); final String newPath = createURL(this.propertyFileFolderUrl, valuePath).toString(); this.property.setProperty(entry.getKey().toString(), newPath); } } } private static URL createURL(final String fullPathNoEndSeparator) { try { return new URL(fullPathNoEndSeparator); } catch (final Exception e) { throw new IllegalArgumentException(e); } } private static URL createURL(final URL context, final String spec) { try { return new URL(context, spec); } catch (final Exception e) { throw new IllegalArgumentException(e); } } }