/*******************************************************************************
* Copyright 2012 Geoscience Australia
*
* 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 au.gov.ga.earthsci.bookmark.io;
import gov.nasa.worldwind.util.WWXML;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import au.gov.ga.earthsci.bookmark.model.Bookmark;
import au.gov.ga.earthsci.bookmark.model.BookmarkList;
import au.gov.ga.earthsci.bookmark.model.Bookmarks;
import au.gov.ga.earthsci.bookmark.model.IBookmarkProperty;
import au.gov.ga.earthsci.bookmark.model.IBookmarks;
import au.gov.ga.earthsci.common.persistence.PersistenceException;
import au.gov.ga.earthsci.common.persistence.Persister;
import au.gov.ga.earthsci.common.util.ConfigurationUtil;
import au.gov.ga.earthsci.common.util.XmlUtil;
import au.gov.ga.earthsci.worldwind.common.util.Validate;
/**
* Helper class to persist the bookmarks model to an XML file
*
* @author James Navin (james.navin@ga.gov.au)
*/
public class BookmarksPersister
{
private BookmarksPersister()
{
}
private static final Logger logger = LoggerFactory.getLogger(BookmarksPersister.class);
private static final String DEFAULT_WORKSPACE_BOOKMARKS_FILENAME = "bookmarks.xml"; //$NON-NLS-1$
private static final String ROOT_NODE_NAME = "document"; //$NON-NLS-1$
private static final Persister persister;
static
{
persister = new Persister();
persister.setIgnoreMissing(true);
persister.setIgnoreNulls(true);
persister.registerNamedExportable(Bookmark.class, "bookmark"); //$NON-NLS-1$
persister.registerNamedExportable(Bookmarks.class, "bookmarks"); //$NON-NLS-1$
persister.registerNamedExportable(BookmarkList.class, "bookmarkList"); //$NON-NLS-1$
persister.registerAdapter(IBookmarkProperty.class, new BookmarkPropertyPersistentAdapter());
persister.registerNamedExportable(IBookmarkProperty.class, "property"); //$NON-NLS-1$
}
/**
* Save the provided bookmarks to the current workspace using the configured
* file name
*
* @param bookmarks
* The bookmarks to save. If <code>null</code> this method will
* have no effect.
*/
public static void saveToWorkspace(IBookmarks bookmarks)
{
if (bookmarks == null)
{
return;
}
try
{
saveBookmarks(bookmarks, ConfigurationUtil.getWorkspaceFile(DEFAULT_WORKSPACE_BOOKMARKS_FILENAME));
}
catch (Exception e)
{
logger.error("Unable to save bookmarks to workspace", e); //$NON-NLS-1$
}
}
/**
* Save the provided bookmarks to the provided file
*
* @param bookmarks
* The bookmarks to save. If <code>null</code> this method will
* have no effect.
* @param file
* The file to save to. Cannot be <code>null</code>.
*
* @throws IOException
* if there is a problem writing to the provided file
* @throws TransformerException
* If there is problem formatting the output XML
* @throws PersistenceException
* If there is a problem persisting the bookmarks
*/
public static void saveBookmarks(IBookmarks bookmarks, File file) throws IOException, TransformerException,
PersistenceException
{
if (bookmarks == null)
{
return;
}
Validate.notNull(file, "An output file is required"); //$NON-NLS-1$
FileOutputStream os = null;
try
{
os = new FileOutputStream(file);
saveBookmarks(bookmarks, os);
}
finally
{
if (os != null)
{
os.close();
}
}
}
/**
* Save the provided bookmarks to the provided output stream.
*
* @param bookmarks
* The bookmarks to save. If <code>null</code> this method will
* have no effect.
* @param os
* The output stream to save to. Must be non-<code>null</code>
* and writable.
*
* @throws IOException
* If there is a problem writing to the output stream
* @throws TransformerException
* If there is problem formatting the output XML
* @throws PersistenceException
* If there is a problem persisting the bookmarks
*/
public static void saveBookmarks(IBookmarks bookmarks, OutputStream os) throws IOException, TransformerException,
PersistenceException
{
if (bookmarks == null)
{
return;
}
Validate.notNull(os, "An output stream is required"); //$NON-NLS-1$
DocumentBuilder documentBuilder = WWXML.createDocumentBuilder(false);
Document document = documentBuilder.newDocument();
Element element = document.createElement(ROOT_NODE_NAME);
document.appendChild(element);
saveBookmarks(bookmarks, element);
XmlUtil.saveDocumentToFormattedStream(document, os);
}
/**
* Save the provided bookmarks as a child of the provided parent element
*
* @param bookmarks
* The bookmarks to save. If <code>null</code> this method has no
* effect.
* @param parent
* The parent element under which to save the XML output
*
* @throws PersistenceException
* If there is a problem persisting the bookmarks
*/
public static void saveBookmarks(IBookmarks bookmarks, Element parent) throws PersistenceException
{
if (bookmarks == null)
{
return;
}
Validate.notNull(parent, "A parent element is required"); //$NON-NLS-1$
persister.save(bookmarks, parent, null);
}
/**
* Load any persisted bookmarks in the current workspace using the
* configured bookmarks file name.
* <p/>
* If a target instance is provided it will be populated with the loaded
* bookmarks data. Otherwise a new instance will be created and returned.
*
* @param target
* The target instance to populate with bookmark data. If
* <code>null</code> a new instance will be created.
*
* @return the loaded bookmarks data
*/
public static IBookmarks loadFromWorkspace(IBookmarks target)
{
File workspaceFile = ConfigurationUtil.getWorkspaceFile(DEFAULT_WORKSPACE_BOOKMARKS_FILENAME);
if (!workspaceFile.exists())
{
logger.debug("No bookmarks file found in workspace. Creating new model."); //$NON-NLS-1$
if (target == null)
{
return new Bookmarks();
}
return target;
}
try
{
return loadBookmarks(workspaceFile, target);
}
catch (Exception e)
{
logger.error("Unable to load bookmarks from workspace", e); //$NON-NLS-1$
}
return target;
}
/**
* Load persisted bookmarks from the given file.
* <p/>
* If a target instance is provided it will be populated with the loaded
* bookmarks data. Otherwise a new instance will be created and returned.
*
* @param file
* The file to load bookmarks from. Must be non-<code>null</code>
* .
* @param target
* The target instance to populate with bookmark data. If
* <code>null</code> a new instance will be created.
*
* @return the loaded bookmarks data
*
* @throws PersistenceException
* If there is a problem un-persisting from the XML
* @throws SAXException
* If there is a problem parsing the XML
* @throws IOException
* If there is a problem reading from the file
*/
public static IBookmarks loadBookmarks(File file, IBookmarks target) throws IOException, SAXException,
PersistenceException
{
Validate.notNull(file, "An input file is required"); //$NON-NLS-1$
FileInputStream is = null;
try
{
is = new FileInputStream(file);
return loadBookmarks(is, target);
}
finally
{
if (is != null)
{
is.close();
}
}
}
/**
* Load persisted bookmarks from the given input stream.
* <p/>
* If a target instance is provided it will be populated with the loaded
* bookmarks data. Otherwise a new instance will be created and returned.
*
* @param is
* The input stream to load bookmarks from. Must be non-
* <code>null</code> and readable.
* @param target
* The target instance to populate with bookmark data. If
* <code>null</code> a new instance will be created.
*
* @return the loaded bookmarks data
*
* @throws PersistenceException
* If there is a problem un-persisting from the XML
* @throws SAXException
* If there is a problem parsing the XML
* @throws IOException
* If there is a problem reading from the stream
*/
public static IBookmarks loadBookmarks(InputStream is, IBookmarks target) throws PersistenceException,
SAXException, IOException
{
Validate.notNull(is, "An input stream is required"); //$NON-NLS-1$
Document document = WWXML.createDocumentBuilder(false).parse(is);
Element parent = document.getDocumentElement();
if (!ROOT_NODE_NAME.equals(parent.getNodeName()))
{
throw new PersistenceException(
"Provided document is not a valid catalog model document. Expected root node " + ROOT_NODE_NAME + " but found " + parent.getNodeName()); //$NON-NLS-1$//$NON-NLS-2$
}
Element element = XmlUtil.getFirstChildElement(parent);
return loadBookmarks(element, target);
}
/**
* Load persisted bookmarks from the given input stream.
* <p/>
* If a target instance is provided it will be populated with the loaded
* bookmarks data. Otherwise a new instance will be created and returned.
*
* @param element
* The root XML element to load from
* @param target
* The target instance to populate with bookmark data. If
* <code>null</code> a new instance will be created.
*
* @return the loaded bookmarks data
*
* @throws PersistenceException
* If there is a problem un-persisting from the XML
* @throws SAXException
* If there is a problem parsing the XML
* @throws IOException
* If there is a problem reading from the stream
*/
public static IBookmarks loadBookmarks(Element element, IBookmarks target) throws PersistenceException
{
IBookmarks loaded = (IBookmarks) persister.load(element, null);
if (target == null)
{
return loaded;
}
target.setLists(loaded.getLists());
return target;
}
}