/*
* gvNIX is an open source tool for rapid application development (RAD).
* Copyright (C) 2010 Generalitat Valenciana
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gvnix.dynamic.configuration.roo.addon.config;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.SortedSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Component;
import org.gvnix.dynamic.configuration.roo.addon.entity.DynProperty;
import org.gvnix.dynamic.configuration.roo.addon.entity.DynPropertyList;
import org.springframework.roo.file.monitor.event.FileDetails;
import org.springframework.roo.process.manager.MutableFile;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.project.Path;
import org.springframework.roo.support.logging.HandlerUtils;
/**
* Abstract dynamic configuration component of property files list.
* <p>
* Extends this class to manage new properties file list values.
* </p>
*
* @author <a href="http://www.disid.com">DISID Corporation S.L.</a> made for <a
* href="http://www.dgti.gva.es">General Directorate for Information
* Technologies (DGTI)</a>
*/
@Component(componentAbstract = true)
public abstract class PropertiesListDynamicConfiguration extends
PropertiesDynamicConfiguration {
private static final Logger LOGGER = HandlerUtils
.getLogger(PropertiesListDynamicConfiguration.class);
/**
* {@inheritDoc}
*/
@Override
public String getFilePath() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public DynPropertyList read() {
DynPropertyList dynProps = new DynPropertyList();
try {
// Get the property files to read from resources
String resources = pathResolver.getIdentifier(
LogicalPath.getInstance(Path.SRC_MAIN_RESOURCES, ""), "");
List<FileDetails> files = getFiles(resources);
for (FileDetails file : files) {
String path = file.getCanonicalPath();
MutableFile mutableFile = fileManager.updateFile(path);
// If managed file not exists, nothing to do
if (mutableFile != null) {
Properties props = new Properties();
props.load(mutableFile.getInputStream());
for (Entry<Object, Object> prop : props.entrySet()) {
dynProps.add(new DynProperty(setKeyValue(prop.getKey()
.toString(), path), prop.getValue().toString()));
}
}
}
}
catch (IOException ioe) {
throw new IllegalStateException(ioe);
}
return dynProps;
}
/**
* {@inheritDoc}
*/
@Override
public void write(DynPropertyList dynProps) {
OutputStream outputStream = null;
// Get the property files to write from resources
String resources = pathResolver.getIdentifier(
LogicalPath.getInstance(Path.SRC_MAIN_RESOURCES, ""), "");
List<FileDetails> files = getFiles(resources);
for (FileDetails f : files) {
try {
// Get properties from the file
MutableFile file = fileManager.updateFile(f.getCanonicalPath());
Properties props = new Properties();
props.load(file.getInputStream());
for (DynProperty dynProp : dynProps) {
// If property belongs to file and exists on file, update it
String key = getKeyValue(dynProp.getKey());
if (isPropertyRelatedToFile(dynProp, file)) {
if (props.containsKey(key)) {
props.put(key, dynProp.getValue());
}
else {
LOGGER.log(
Level.WARNING,
"Property key "
.concat(dynProp.getKey())
.concat(" to put value not exists on file"));
}
}
}
outputStream = file.getOutputStream();
props.store(outputStream, null);
}
catch (IOException ioe) {
throw new IllegalStateException(ioe);
}
finally {
IOUtils.closeQuietly(outputStream);
}
}
}
/**
* Is a dynamic property related to the file ?
*
* @param dynProp Dynamic property
* @param file Mutable file
* @return Is property related to file ?
*/
protected boolean isPropertyRelatedToFile(DynProperty dynProp,
MutableFile file) {
if (getFileIndentifierFromKey(dynProp.getKey()).equals(
getFileIdentifierFromPath(file.getCanonicalPath()))) {
return true;
}
return false;
}
/**
* Get included files on a path.
*
* @param source Initial path to search files
* @return Files list
*/
protected List<FileDetails> getFiles(String source) {
List<FileDetails> result = new ArrayList<FileDetails>();
try {
// Find all paths from the source path
SortedSet<FileDetails> paths = fileManager
.findMatchingAntPath(source + "/*");
for (FileDetails path : paths) {
// This path name is a file to include ?
String pathName = path.getCanonicalPath();
if (include(pathName)) {
// File to include !
result.add(path);
}
else {
// Iterate child paths (only for folders)
result.addAll(getFiles(pathName));
}
}
}
catch (IllegalArgumentException iae) {
// Path is a a file: nothing to do
LOGGER.finest("Path element file");
}
return result;
}
/**
* There is a file to include on dynamic configurations ?
*
* @param path File path to check
* @return Include on dynamic configuration ?
*/
protected boolean include(String path) {
return getFileName(path).startsWith(getFilePrefix())
&& path.endsWith(getFileSufix());
}
/**
* Set key value to set on a dynamic property considering file name.
*
* @param key Original key value
* @param path File path
* @return New key value
*/
protected String setKeyValue(String key, String path) {
return getPropertyTargetPrefix()
.concat(getFileIdentifierFromPath(path)).concat(
key.substring(getPropertySourcePrefix().length() - 1,
key.length()));
}
/**
* Get the file identifier from the property key
*
* @param path File path
* @return File identifier
*/
protected String getFileIndentifierFromKey(String key) {
String sufix = key.substring(getPropertyTargetPrefix().length(),
key.length());
return sufix.substring(0, sufix.indexOf('.'));
}
/**
* Get key value from a dynamic property.
*
* @param key Original key value
* @return New key value
*/
protected String getKeyValue(String key) {
return getPropertySourcePrefix().concat(
key.substring(getPropertyTargetPrefix().length()
+ getFileIndentifierFromKey(key).length() + 1));
}
/**
* Get the file identifier from the file path.
*
* @param path File path
* @return File identifier
*/
protected String getFileIdentifierFromPath(String path) {
String fileName = getFileName(path);
return fileName.substring(fileName.indexOf(getFilePrefix()),
fileName.lastIndexOf(getFileSufix()));
}
/**
* Get the file name part from a path.
*
* @param path File path
* @return File name part
*/
protected String getFileName(String path) {
return path.substring(path.lastIndexOf('/') + 1);
}
public abstract String getFileSufix();
public abstract String getFilePrefix();
public abstract String getPropertyTargetPrefix();
public abstract String getPropertySourcePrefix();
}