/*
* Created on 24 mai 2005
*
* Copyright (c) 2005, PMD for Eclipse Development Team
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed in part by support from
* the Defense Advanced Research Project Agency (DARPA)"
* * Neither the name of "PMD for Eclipse Development Team" nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.sourceforge.pmd.eclipse.ui.views;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import net.sourceforge.pmd.eclipse.plugin.PMDPlugin;
import net.sourceforge.pmd.eclipse.ui.nls.StringKeys;
import net.sourceforge.pmd.util.NumericConstants;
import net.sourceforge.pmd.util.StringUtil;
import org.eclipse.core.runtime.IPath;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;
/**
* Provides functions to save the state of a View during a session, even when the view is closed and re-opened
* saves the state in an XML-File in the Plugins-Path (Standard: .metadata in the workspace)
*
* @author SebastianRaffel ( 24.05.2005 ), Philippe Herlin, Sven Jacob
*
*/
public class ViewMemento {
private final IPath path; // NOPMD by Herlin on 11/10/06 00:15
private final File file;
private XMLMemento memento;
protected static final String XML_PREFIX = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
protected static final String LIST_SEPARATOR = ":";
protected static final String MEMENTO_PREFIX = "memento";
protected static final String ATTRIBUTE_PREFIX = "attribute";
protected static final String ATTR_NAME = "name";
protected static final String ATTR_VALUE = "value";
/**
* Constructor Searches for the XML-File, where the Memento should be saved and creates it if there is none
*
* @param type, a String identifying the View, used for the File's Name
*/
public ViewMemento(String type) {
this.path = PMDPlugin.getDefault().getStateLocation();
this.file = new File(this.path.toString(), type);
// we check for an existing XML-File
// and create one, if needed
if (!this.file.exists() || !checkForXMLFile(this.file)) {
createNewFile(this.file);
}
// then we create a ReadRoot for the Memento
FileReader reader = null;
try {
reader = new FileReader(file);
this.memento = XMLMemento.createReadRoot(reader);
} catch (WorkbenchException wbe) {
PMDPlugin.getDefault().logError(StringKeys.ERROR_VIEW_EXCEPTION + this.toString(), wbe);
} catch (FileNotFoundException fnfe) {
PMDPlugin.getDefault().logError(
StringKeys.ERROR_FILE_NOT_FOUND + path.toString() + "/" + type + " in " + this.toString(), fnfe);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) { // NOPMD by Herlin on 10/10/06 23:55
// Ignored
}
}
}
// Validate that the memento has been built
if (this.memento == null) {
throw new IllegalStateException("Memento has not been built correctly. Check error log for details");
}
}
/**
* Creates a new XML-Structure in a given File
*
* @param file
*/
protected final void createNewFile(File file) {
FileWriter writer = null;
try {
writer = new FileWriter(file);
writer.write(XML_PREFIX + "\n" + "<" + MEMENTO_PREFIX + "/>");
} catch (IOException ioe) {
PMDPlugin.getDefault().logError(StringKeys.ERROR_IO_EXCEPTION + this.toString(), ioe);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) { // NOPMD by Herlin on 10/10/06 23:55
// ignored
}
}
}
}
/**
* Checks for an XML-Structure in a File
*
* @param file
* @return true, if the File is a XML-File we can use, false otherwise
*/
protected final boolean checkForXMLFile(File file) {
boolean isXmlFile = false;
BufferedReader contentReader = null;
try {
contentReader = new BufferedReader(new FileReader(file));
while (contentReader.ready()) {
String line = contentReader.readLine();
if (line != null && line.length() != 0) {
// the first Line of Text has to be the XML-Prefix
isXmlFile = XML_PREFIX.equalsIgnoreCase(line);
break;
}
}
} catch (FileNotFoundException fnfe) {
PMDPlugin.getDefault().logError(StringKeys.ERROR_FILE_NOT_FOUND + file.toString() + " in " + this.toString(),
fnfe);
} catch (IOException ioe) {
PMDPlugin.getDefault().logError(StringKeys.ERROR_IO_EXCEPTION + this.toString(), ioe);
} finally {
if (contentReader != null) {
try {
contentReader.close();
} catch (IOException e) { // NOPMD by Herlin on 10/10/06 23:57
// Ignored
}
}
}
return isXmlFile;
}
/**
* Saves the Memento into the File
*
* @param type
*/
public void save() {
if (this.memento != null) {
FileWriter writer = null;
try {
writer = new FileWriter(this.file);
this.memento.save(writer);
} catch (IOException ioe) {
PMDPlugin.getDefault().logError(StringKeys.ERROR_IO_EXCEPTION + this.toString(), ioe);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) { // NOPMD by Herlin on 11/10/06 00:00
// Ignored
}
}
}
}
}
/**
* Returns a Memento with the given Attribute
*
* @param name
* @return a Memento
*/
private IMemento getAttribute(String name) {
final IMemento[] mementos = this.memento.getChildren(ATTRIBUTE_PREFIX);
IMemento mem = null;
for (IMemento memento2 : mementos) {
final String attrName = memento2.getString(ATTR_NAME);
if (name.equalsIgnoreCase(attrName)) {
mem = memento2;
}
}
if (mem == null) {
mem = this.memento.createChild(ATTRIBUTE_PREFIX);
mem.putString(ATTR_NAME, name);
}
return mem;
}
/**
* Puts a String into a Memento
*
* @param key
* @param value
*/
public void putString(String key, String value) {
final IMemento mem = getAttribute(key);
mem.putString(ATTR_VALUE, value);
}
/**
* Puts an Integer into a Memento
*
* @param key
* @param value
*/
public void putInteger(String key, int value) {
final IMemento mem = getAttribute(key);
mem.putInteger(ATTR_VALUE, value);
}
/**
* Puts a Float into a Memento
*
* @param key
* @param value
*/
public void putFloat(String key, float value) {
final IMemento mem = getAttribute(key);
mem.putFloat(ATTR_VALUE, value);
}
/**
* puts an List into a Memento, the List is changed into a delimited String
*
* @param key
* @param valueList
*/
public <T extends Object> void putList(String key, List<T> valueList) {
if (valueList.isEmpty()) {
putString(key, ""); // even necessary?
return;
}
final StringBuilder sb = new StringBuilder(String.valueOf(valueList.get(0)));
for (int k = 1; k < valueList.size(); k++) {
sb.append(LIST_SEPARATOR).append(valueList.get(k));
}
putString(key, sb.toString());
}
/**
* Gets a String from a Memento
*
* @param key
* @return a String with the Value
*/
public String getString(String key) {
final IMemento mem = getAttribute(key);
return mem.getString(ATTR_VALUE);
}
/**
* Gets an Integer From a Memento
*
* @param key
* @return an Integer with the Value
*/
public Integer getInteger(String key) {
final IMemento mem = getAttribute(key);
return mem.getInteger(ATTR_VALUE);
}
/**
* Returns a Float from a Memento
*
* @param key
* @return a Float with the Value
*/
public Float getFloat(String key) {
final IMemento mem = getAttribute(key);
return mem.getFloat(ATTR_VALUE);
}
/**
* Returns an List of Integers from a Memento
*
* @param key
* @return List of Integer-values
*/
public List<Integer> getIntegerList(String key) {
final List<Integer> valuelist = new ArrayList<Integer>();
final String valueString = getString(key);
if (valueString != null) {
final String[] objects = valueString.split(LIST_SEPARATOR);
for (String object : objects) {
if (StringUtil.isEmpty(object) || "null".equals(object)) {
valuelist.add(NumericConstants.ZERO); // NOPMD by Herlin on 11/10/06 00:13
} else {
valuelist.add(Integer.valueOf(object)); // NOPMD by Herlin on 11/10/06 00:14
}
}
}
return valuelist;
}
/**
* Returns an List of Strings from a Memento
*
* @param key
* @return a List of String values
*/
public List<String> getStringList(String key) {
List<String> valuelist = Collections.emptyList();
final String valueString = getString(key);
if (valueString != null) {
valuelist = new ArrayList<String>(Arrays.asList(valueString.split(LIST_SEPARATOR)));
}
return valuelist;
}
}