/*
* � Copyright IBM Corp. 2011
*
* 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 com.ibm.xsp.extlib.designer.common.properties;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Properties;
import com.ibm.commons.iloader.node.DataChangeNotifier;
import com.ibm.commons.util.FastStringBuffer;
import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.extlib.designer.DesignerExtensionLogger;
/**
* @author mblout
*
*/
public class PreservingProperties {
String propertiesAsString;
final FastStringBuffer fsb = new FastStringBuffer();
final Properties javaioprops = new Properties();
final ContentFacade facade;
final boolean saveOnSet; // if false, an explicit call to save() must be made to write
boolean rebuildjProps = false;
boolean isDirty = false;
String ENCODING = "ISO-8859-1"; //$NON-NLS-1$
public interface ContentFacade {
String getName ();
InputStream getContents ();
void setContents (InputStream in);
void append (InputStream in);
}
public PreservingProperties(ContentFacade provider, boolean saveOnSet) {
this.facade = provider;
this.saveOnSet = saveOnSet;
fsb.clear();
loadAsString();
}
public String getName() {
return facade.getName();
}
/**
* in theory, this should only load once at the beginning, and from then on will be
* maintained by the class
*
*/
public boolean loadAsString() {
boolean ok = true;
InputStream in = null;
try {
in = facade.getContents();
byte[] b = new byte[4096];
for (int n; (n = in.read(b)) != -1;) {
fsb.append(new String(b, 0, n));
}
}
catch(Exception e) {
ok = false;
fsb.clear();
DesignerExtensionLogger.CORE_LOGGER.error(e, "exception reading properties from stream"); // $NLE-PropertiesUtils.exceptionreadingpropertiesfromstream-1$
}
rebuildjProps = true;
propertiesAsString = fsb.toString();
return ok;
}
public String set(String key, String value) {
return set(key, value, null);
}
public String set(String key, String value, DataChangeNotifier notifier) {
int len = propertiesAsString.length();
getProperties();
isDirty = true;
if (null == value) {
javaioprops.remove(key);
}
else {
javaioprops.setProperty(key, value);
}
// @TODO: this is copied from XSPPropBeanLoader - need to refactor
boolean bRemove = !javaioprops.containsKey(key);
String keyNameEquals = key + "="; //$NON-NLS-1$
fsb.clear();
int loc = StringUtil.indexOfIgnoreCase(propertiesAsString, keyNameEquals);
// need to add the property
if (loc == -1 && !bRemove) {
fsb.append(propertiesAsString);
if (!propertiesAsString.endsWith("\n")) //$NON-NLS-1$
fsb.append("\r\n"); //$NON-NLS-1$
fsb.append(keyNameEquals);
fsb.append(value);
fsb.append("\r\n"); //$NON-NLS-1$
//@todo: call notifier methods in PreservingProperties
// if (null != notifier)
// notifier.notifyItemInserted(this, member, position, exclude)
}
else if (bRemove) {
int nextLF = StringUtil.indexOfIgnoreCase(propertiesAsString, "\r", loc); //$NON-NLS-1$
// always take up to this property
fsb.append(propertiesAsString.substring(0, loc));
// if we're at the end, we're done, otherwise, get everything *after* this prop
if (nextLF != -1) {
if ((nextLF+2) < len)
fsb.append(propertiesAsString.substring(nextLF+2));
}
}
else { // need to modify the property
loc += keyNameEquals.length();
// property starts after the equals...
// need to find out where it ends (next line feed)
int nextLF = StringUtil.indexOfIgnoreCase(propertiesAsString, "\r", loc); //$NON-NLS-1$
String rest = null;
if (nextLF != -1)
rest = propertiesAsString.substring(nextLF);
fsb.append(propertiesAsString.substring(0, loc));
fsb.append(value);
if (rest != null)
fsb.append(rest);
}
rebuildjProps = true;
propertiesAsString = fsb.toString();
// persist
if (saveOnSet) {
save();
}
return propertiesAsString;
}
/**
* @return
*/
public Properties getProperties() {
if (rebuildjProps) {
ByteArrayInputStream bs = null;
try{
byte[] bytes = propertiesAsString.getBytes(ENCODING);
bs = new ByteArrayInputStream(bytes);
javaioprops.clear();
try {
javaioprops.load(bs);
} catch (IOException e) {
DesignerExtensionLogger.CORE_LOGGER.error(e, "exception reading properties"); // $NLE-PropertiesUtils.exceptionreadingproperties-1$
}
}
catch(UnsupportedEncodingException e) {
DesignerExtensionLogger.CORE_LOGGER.error(e, "exception reading properties"); // $NLE-PropertiesUtils.exceptionreadingproperties-1$
}
finally{
if(bs != null){
try {
bs.close();
} catch (IOException e) {
DesignerExtensionLogger.CORE_LOGGER.error(e, "exception closing properties stream"); // $NLE-PropertiesUtils.exceptionclosingpropertiesstream-1$
}
}
}
}
rebuildjProps = false;
return javaioprops;
}
/**
*
* @return
*/
public boolean isDirty() {
return isDirty;
}
/**
*
*/
public void save() {
try {
byte[] bytes = propertiesAsString.getBytes(ENCODING);
InputStream in = new ByteArrayInputStream(bytes);
facade.setContents(in);
isDirty = false;
}
catch(UnsupportedEncodingException e) {
DesignerExtensionLogger.CORE_LOGGER.error(e, "exception writing properties"); // $NLE-PropertiesUtils.exceptionwritingproperties-1$
}
}
}