/* ********************************************************************** **
** Copyright notice **
** **
** (c) 2005-2006 RSSOwl Development Team **
** http://www.rssowl.org/ **
** **
** All rights reserved **
** **
** This program and the accompanying materials are made available under **
** the terms of the Eclipse Public License v1.0 which accompanies this **
** distribution, and is available at: **
** http://www.rssowl.org/legal/epl-v10.html **
** **
** A copy is found in the file epl-v10.html and important notices to the **
** license from the team is found in the textfile LICENSE.txt distributed **
** in this package. **
** **
** This copyright notice MUST APPEAR in all copies of the file! **
** **
** Contributors: **
** RSSOwl Development Team - initial API and implementation **
** **
** ********************************************************************** */
package org.rssowl.core.internal.persist.migration;
import org.eclipse.core.runtime.IProgressMonitor;
import org.rssowl.core.internal.InternalOwl;
import org.rssowl.core.internal.persist.service.ConfigurationFactory;
import org.rssowl.core.internal.persist.service.Migration;
import org.rssowl.core.model.internal.db4o.Counter;
import org.rssowl.core.model.internal.preferences.Preference;
import org.rssowl.core.model.internal.search.SearchCondition;
import org.rssowl.core.model.internal.search.SearchField;
import org.rssowl.core.model.internal.search.SearchValueType;
import org.rssowl.core.model.internal.types.AbstractEntity;
import org.rssowl.core.model.internal.types.Attachment;
import org.rssowl.core.model.internal.types.BookMark;
import org.rssowl.core.model.internal.types.Category;
import org.rssowl.core.model.internal.types.ConditionalGet;
import org.rssowl.core.model.internal.types.ExtendableType;
import org.rssowl.core.model.internal.types.Feed;
import org.rssowl.core.model.internal.types.Folder;
import org.rssowl.core.model.internal.types.Guid;
import org.rssowl.core.model.internal.types.Image;
import org.rssowl.core.model.internal.types.Label;
import org.rssowl.core.model.internal.types.Mark;
import org.rssowl.core.model.internal.types.News;
import org.rssowl.core.model.internal.types.Person;
import org.rssowl.core.model.internal.types.SearchMark;
import org.rssowl.core.model.internal.types.Source;
import org.rssowl.core.model.search.ISearchField;
import org.rssowl.core.model.search.SearchSpecifier;
import org.rssowl.core.model.types.IAttachment;
import org.rssowl.core.model.types.IBookMark;
import org.rssowl.core.model.types.ICategory;
import org.rssowl.core.model.types.IFeed;
import org.rssowl.core.model.types.IFolder;
import org.rssowl.core.model.types.IImage;
import org.rssowl.core.model.types.ILabel;
import org.rssowl.core.model.types.IMark;
import org.rssowl.core.model.types.INews;
import org.rssowl.core.model.types.IPerson;
import org.rssowl.core.model.types.ISearchMark;
import org.rssowl.core.model.types.ISource;
import org.rssowl.core.persist.IFolderChild;
import org.rssowl.core.persist.IModelFactory;
import org.rssowl.core.persist.IPreference;
import org.rssowl.core.persist.ISearchCondition;
import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import com.db4o.config.Configuration;
import com.db4o.query.Query;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Migration from version 0 to version 1.
*
* @inheritDoc
*/
public class Migration0To1 implements Migration {
/*
* TODO Cleanup after tagging:
*
* 0) Delete core.model.types package.
* 1) Delete core.model.internal.types package.
* 2) Delete core.model.search package.
* 3) Delete core.model.internal.search package.
* 4) Delete core.model.internal.preferences package.
* 5) Delete core.model.internal.db4o package.
*/
/**
* Creates an instance of this class.
*/
public Migration0To1() {
super();
}
@SuppressWarnings("unchecked")
private List<IFolderChild> getFolderChildren(org.rssowl.core.persist.IFolder folder, String fieldName) {
return (List<IFolderChild>) MigrationHelper.getFieldValue(folder, fieldName);
}
private IPreference convertPref(Preference oldPref) {
String[] values = oldPref.getValues().toArray(new String[oldPref.getValues().size()]);
IPreference.Type type = null;
switch (oldPref.getType()) {
case BOOLEAN:
type = IPreference.Type.BOOLEAN;
break;
case INTEGER:
case INTEGER_ARRAY:
type = IPreference.Type.INTEGER;
break;
case LONG:
case LONG_ARRAY:
type = IPreference.Type.LONG;
break;
case STRING:
case STRING_ARRAY:
type = IPreference.Type.STRING;
break;
default:
throw new IllegalArgumentException(oldPref.getType().toString());
}
IPreference newPref = new org.rssowl.core.internal.persist.Preference(oldPref.getKey());
MigrationHelper.setField(newPref, "fValues", values);
MigrationHelper.setField(newPref, "fType", type);
return newPref;
}
public int getDestinationFormat() {
return 1;
}
public int getOriginFormat() {
return 0;
}
//TODO Report progress
public boolean migrate(ConfigurationFactory configFactory, String dbFileName, IProgressMonitor progressMonitor) {
progressMonitor.beginTask("Migrating data", 100);
ObjectContainer oc = Db4o.openFile(configFactory.createConfiguration(), dbFileName);
/* Copy all folder and mark properties to map */
Map<Long, Map<String, ?>> idPropertiesMap = new HashMap<Long, Map<String, ?>>();
for (Folder folder : oc.query(Folder.class)) {
idPropertiesMap.put(folder.getId(), folder.getProperties());
}
for (Mark mark : oc.query(Mark.class)) {
idPropertiesMap.put(mark.getId(), mark.getProperties());
}
oc.close();
Configuration c = Db4o.newConfiguration();
/* core.model.types to core.persist */
c.objectClass(IAttachment.class).rename(org.rssowl.core.persist.IAttachment.class.getName());
c.objectClass(IBookMark.class).rename(org.rssowl.core.persist.IBookMark.class.getName());
c.objectClass(ICategory.class).rename(org.rssowl.core.persist.ICategory.class.getName());
c.objectClass(IFeed.class).rename(org.rssowl.core.persist.IFeed.class.getName());
c.objectClass(IFolder.class).rename(org.rssowl.core.persist.IFolder.class.getName());
c.objectClass(IImage.class).rename(org.rssowl.core.persist.IImage.class.getName());
c.objectClass(ILabel.class).rename(org.rssowl.core.persist.ILabel.class.getName());
c.objectClass(IMark.class).rename(org.rssowl.core.persist.IMark.class.getName());
c.objectClass(INews.class).rename(org.rssowl.core.persist.INews.class.getName());
c.objectClass(INews.State.class).rename(org.rssowl.core.persist.INews.State.class.getName());
c.objectClass(IPerson.class).rename(org.rssowl.core.persist.IPerson.class.getName());
c.objectClass(ISearchMark.class).rename(org.rssowl.core.persist.ISearchMark.class.getName());
c.objectClass(ISource.class).rename(org.rssowl.core.persist.ISource.class.getName());
/* core.model.internal.types to core.internal.persist */
c.objectClass(AbstractEntity.class).rename(org.rssowl.core.internal.persist.AbstractEntity.class.getName());
c.objectClass(Attachment.class).rename(org.rssowl.core.internal.persist.Attachment.class.getName());
c.objectClass(BookMark.class).rename(org.rssowl.core.internal.persist.BookMark.class.getName());
c.objectClass(Category.class).rename(org.rssowl.core.internal.persist.Category.class.getName());
c.objectClass(ConditionalGet.class).rename(org.rssowl.core.internal.persist.ConditionalGet.class.getName());
c.objectClass(Feed.class).rename(org.rssowl.core.internal.persist.Feed.class.getName());
c.objectClass(Folder.class).rename(org.rssowl.core.internal.persist.Folder.class.getName());
c.objectClass(Guid.class).rename(org.rssowl.core.internal.persist.Guid.class.getName());
c.objectClass(Image.class).rename(org.rssowl.core.internal.persist.Image.class.getName());
c.objectClass(Label.class).rename(org.rssowl.core.internal.persist.Label.class.getName());
c.objectClass(Mark.class).rename(org.rssowl.core.internal.persist.Mark.class.getName());
c.objectClass(News.class).rename(org.rssowl.core.internal.persist.News.class.getName());
c.objectClass(ExtendableType.class).rename(org.rssowl.core.internal.persist.AbstractEntity.class.getName());
c.objectClass(Person.class).rename(org.rssowl.core.internal.persist.Person.class.getName());
c.objectClass(SearchMark.class).rename(org.rssowl.core.internal.persist.SearchMark.class.getName());
c.objectClass(Source.class).rename(org.rssowl.core.internal.persist.Source.class.getName());
/* Search-related classes*/
c.objectClass(SearchSpecifier.class).rename(org.rssowl.core.persist.SearchSpecifier.class.getName());
c.objectClass(SearchCondition.class).rename(org.rssowl.core.internal.persist.SearchCondition.class.getName());
c.objectClass(ISearchField.class).rename(org.rssowl.core.persist.ISearchField.class.getName());
c.objectClass(SearchField.class).rename(org.rssowl.core.internal.persist.SearchField.class.getName());
c.objectClass(SearchValueType.class).rename(org.rssowl.core.internal.persist.SearchValueType.class.getName());
/* Counter */
c.objectClass(Counter.class).rename(org.rssowl.core.internal.persist.service.Counter.class.getName());
oc = Db4o.openFile(c, dbFileName);
oc.close();
/* 10 */
progressMonitor.worked(10);
oc = Db4o.openFile(configFactory.createConfiguration(), dbFileName);
/* Preference */
for (Preference pref : oc.query(Preference.class)) {
oc.activate(pref, Integer.MAX_VALUE);
oc.ext().set(convertPref(pref), Integer.MAX_VALUE);
oc.delete(pref);
}
oc.commit();
/* 20 */
progressMonitor.worked(10);
for (org.rssowl.core.persist.ISearchField searchField : oc.query(org.rssowl.core.internal.persist.SearchField.class)) {
oc.activate(searchField, Integer.MAX_VALUE);
String entityName = searchField.getEntityName();
entityName = entityName.replace("core.model.types", "core.persist");
MigrationHelper.setField(searchField, "fEntityName", entityName);
oc.ext().set(searchField, Integer.MAX_VALUE);
}
oc.commit();
/* 30 */
progressMonitor.worked(10);
for (org.rssowl.core.persist.ISearchCondition searchCond : oc.query(org.rssowl.core.internal.persist.SearchCondition.class)) {
oc.activate(searchCond, Integer.MAX_VALUE);
int searchSpecOrdinal = searchCond.getSpecifier().ordinal();
org.rssowl.core.persist.SearchSpecifier searchSpec = org.rssowl.core.persist.SearchSpecifier.values()[searchSpecOrdinal];
MigrationHelper.setField(searchCond, "fSpecifier", searchSpec);
oc.ext().set(searchCond, Integer.MAX_VALUE);
}
oc.commit();
/* 40 */
progressMonitor.worked(10);
List<org.rssowl.core.persist.IFolder> folders = new ArrayList<org.rssowl.core.persist.IFolder>();
for (org.rssowl.core.persist.IFolder folder : oc.query(org.rssowl.core.internal.persist.Folder.class)) {
oc.activate(folder, Integer.MAX_VALUE);
List<IFolderChild> children = new ArrayList<IFolderChild>(getFolderChildren(folder, "fFolders"));
MigrationHelper.setField(folder, "fFolders", null);
children.addAll(getFolderChildren(folder, "fMarks"));
MigrationHelper.setField(folder, "fMarks", null);
MigrationHelper.setField(folder, "fChildren", children);
folders.add(folder);
}
/* Only save folders once they have all been updated */
for (org.rssowl.core.persist.IFolder folder : folders) {
oc.ext().set(folder, Integer.MAX_VALUE);
}
List<org.rssowl.core.persist.IMark> marks = new ArrayList<org.rssowl.core.persist.IMark>();
for (org.rssowl.core.persist.IMark mark : oc.query(org.rssowl.core.internal.persist.Mark.class)) {
oc.activate(mark, Integer.MAX_VALUE);
org.rssowl.core.persist.IFolder parent = (org.rssowl.core.persist.IFolder) MigrationHelper.getFieldValue(mark, "fFolder");
MigrationHelper.setField(mark, "fFolder", null);
MigrationHelper.setField(mark, "fParent", parent);
/*
* If ISearchMark contains a search condition with INews.State, replace
* it with an EnumSet<INews.State>.
*/
if (mark instanceof org.rssowl.core.persist.ISearchMark) {
org.rssowl.core.persist.ISearchMark searchMark = (org.rssowl.core.persist.ISearchMark) mark;
EnumSet<org.rssowl.core.persist.INews.State> states = EnumSet.noneOf(org.rssowl.core.persist.INews.State.class);
List<ISearchCondition> searchConds = new ArrayList<ISearchCondition>();
for (ISearchCondition searchCond : searchMark.getSearchConditions()) {
org.rssowl.core.persist.ISearchField searchField = searchCond.getField();
if (searchField.getEntityName().equals(org.rssowl.core.persist.INews.class.getName()) && searchField.getId() == INews.STATE) {
states.add((org.rssowl.core.persist.INews.State) searchCond.getValue());
}
else {
searchConds.add(searchCond);
}
}
if (!states.isEmpty()) {
IModelFactory factory = InternalOwl.getDefault().getModelFactory();
org.rssowl.core.persist.ISearchField field = factory.createSearchField(INews.STATE, org.rssowl.core.persist.INews.class.getName());
searchConds.add(factory.createSearchCondition(field, org.rssowl.core.persist.SearchSpecifier.IS, states));
MigrationHelper.setField(mark, "fSearchConditions", searchConds);
}
}
marks.add(mark);
}
/* Only save folders once they have all been updated */
for (org.rssowl.core.persist.IMark mark : marks) {
oc.ext().set(mark, Integer.MAX_VALUE);
}
oc.commit();
/* 80 */
progressMonitor.worked(40);
for (Map.Entry<Long, Map<String, ?>> entry : idPropertiesMap.entrySet()) {
Query query = oc.query();
query.constrain(org.rssowl.core.internal.persist.AbstractEntity.class);
query.descend("fId").constrain(entry.getKey()); //$NON-NLS-1$
List<?> list = query.execute();
org.rssowl.core.internal.persist.AbstractEntity entity = (org.rssowl.core.internal.persist.AbstractEntity) list.get(0);
oc.activate(entity, Integer.MAX_VALUE);
for (Map.Entry<String, ?> valueEntry : entry.getValue().entrySet()) {
entity.setProperty(valueEntry.getKey(), valueEntry.getValue());
}
oc.ext().set(entity, Integer.MAX_VALUE);
}
/* 90 */
progressMonitor.worked(10);
oc.close();
/* Disable indices to force them to be re-created */
Configuration config = configFactory.createConfiguration();
config.objectClass(org.rssowl.core.internal.persist.BookMark.class).objectField("fFeedLink").indexed(false); //$NON-NLS-1$
config.objectClass(org.rssowl.core.internal.persist.ConditionalGet.class).objectField("fLink").indexed(false); //$NON-NLS-1$
config.objectClass(org.rssowl.core.internal.persist.Preference.class).objectField("fKey").indexed(false); //$NON-NLS-1$
config.objectClass(org.rssowl.core.internal.persist.Feed.class).objectField("fLinkText").indexed(false);
config.objectClass(org.rssowl.core.internal.persist.News.class).objectField("fLinkText").indexed(false); //$NON-NLS-1$
config.objectClass(org.rssowl.core.internal.persist.News.class).objectField("fGuidValue").indexed(false);
config.objectClass(org.rssowl.core.internal.persist.News.class).objectField("fFeedLink").indexed(false); //$NON-NLS-1$
config.objectClass(org.rssowl.core.internal.persist.News.class).objectField("fStateOrdinal").indexed(false); //$NON-NLS-1$
oc = Db4o.openFile(config, dbFileName);
/* Access classes with index */
ObjectSet<org.rssowl.core.internal.persist.BookMark> markSet = oc.query(org.rssowl.core.internal.persist.BookMark.class);
if (markSet.hasNext())
markSet.next().getName();
ObjectSet<org.rssowl.core.internal.persist.ConditionalGet> condGetSet = oc.query(org.rssowl.core.internal.persist.ConditionalGet.class);
if (condGetSet.hasNext())
condGetSet.next().getLink();
ObjectSet<org.rssowl.core.internal.persist.Preference> prefSet = oc.query(org.rssowl.core.internal.persist.Preference.class);
if (prefSet.hasNext())
prefSet.next().getKey();
ObjectSet<org.rssowl.core.internal.persist.Feed> feedSet = oc.query(org.rssowl.core.internal.persist.Feed.class);
if (feedSet.hasNext())
feedSet.next().getLink();
ObjectSet<org.rssowl.core.internal.persist.News> newsSet = oc.query(org.rssowl.core.internal.persist.News.class);
if (newsSet.hasNext())
newsSet.next().getLink();
oc.close();
/* 100 */
progressMonitor.worked(10);
return true;
}
}