/**
* Copyright (c) 2005-2008 Aptana, Inc.
*
* 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.eclipse.org/legal/epl-v10.html. If redistributing this code,
* this entire header must remain intact.
*/
package com.aptana.ide.intro;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.aptana.ide.core.IdeLog;
import com.aptana.ide.update.FeatureUtil;
import com.aptana.ide.update.manager.IPlugin;
/**
* @author Kevin Sawicki (ksawicki@aptana.com)
*/
public class FeatureChangeManager
{
private static FeatureChangeManager manager = null;
/**
* FEATURE_STORE_PATH
*/
public static final String FEATURE_STORE_PATH = ".features"; //$NON-NLS-1$
private List<FeatureChange> changeList;
private boolean changed;
private FeatureChangeManager()
{
List<IPlugin> plugins = FeatureUtil.getInstalledFeatures();
try
{
List<FeatureChange> changes = compareToStore(plugins);
changed = !changes.isEmpty();
if (changed)
{
this.changeList = changes;
updateStore(plugins);
}
else
{
this.changeList = null;
}
}
catch (Exception e)
{
IdeLog.logInfo(IntroPlugin.getDefault(), e.getMessage());
// Error so don't bring updates to the user, reset until next time
updateStore(plugins);
changed = false;
this.changeList = null;
}
}
/**
* Gets the feature change manager
*
* @return - manager instance
*/
public synchronized static FeatureChangeManager getManager()
{
if (manager == null)
{
manager = new FeatureChangeManager();
}
return manager;
}
/**
* True if features have changed since last startup
*
* @return - true if features changed and a changelist will be available
*/
public boolean areFeaturesChanged()
{
return changed;
}
/**
* Gets the feature change list if changes are present
*
* @return - List of FeatureChanges
*/
public List<FeatureChange> getFeatureChangeList()
{
return this.changeList;
}
private void updateStore(List<IPlugin> plugins)
{
HashMap<String, String> newIdsToVersion = new HashMap<String, String>();
for (IPlugin ref : plugins)
{
newIdsToVersion.put(ref.getId(), ref.getVersion());
IdeLog.logInfo(IntroPlugin.getDefault(), MessageFormat.format(Messages.FeatureChangeManager_INF_Feature,
ref.getId(), ref.getVersion()));
}
saveFeatureInformation(newIdsToVersion);
}
private List<FeatureChange> compareToStore(List<IPlugin> plugins) throws FileNotFoundException, IOException,
ClassNotFoundException
{
Map<String, String> idToVersions = getStoredVersions();
List<FeatureChange> changes = new ArrayList<FeatureChange>();
for (IPlugin ref : plugins)
{
String currentVersion = ref.getVersion();
FeatureChange change = null;
if (idToVersions.containsKey(ref.getId()))
{
String previous = (String) idToVersions.get(ref.getId());
if (!previous.equals(currentVersion))
{
change = new FeatureChange(ref.getId(), ref.getName(), previous, currentVersion, getProvider(ref));
}
}
else
{
// Add as a newly installed feature
change = new FeatureChange(ref.getId(), ref.getName(), null, currentVersion, getProvider(ref));
}
if (change != null)
{
changes.add(change);
}
}
return changes;
}
@SuppressWarnings("unchecked")
private Map<String, String> getStoredVersions() throws IOException, ClassNotFoundException
{
File bundleFile = IntroPlugin.getDefault().getStateLocation().append(FEATURE_STORE_PATH).toFile();
if (!bundleFile.exists())
throw new IOException("Feature store does not exist"); //$NON-NLS-1$
ObjectInputStream ois = null;
try
{
ois = new ObjectInputStream(new FileInputStream(bundleFile));
Object obj = ois.readObject();
if (obj instanceof Map<?, ?>)
{
return (Map<String, String>) obj;
}
else
throw new IOException("File empty or corrupted"); //$NON-NLS-1$
}
finally
{
if (ois != null)
ois.close();
}
}
/**
* This is a hack so that our plugins show as Aptana as provider since we don't retain that info in IPlugin right
* now.
*
* @param ref
* @return
*/
private String getProvider(IPlugin ref)
{
if (ref == null || ref.getId() == null)
return "";
if (ref.getId().contains("aptana") || ref.getId().contains("radrails") || ref.getId().contains("rubypeople")
|| ref.getId().contains("pydev"))
return "Aptana, Inc.";
return "";
}
private void saveFeatureInformation(HashMap<String, String> idToVersions)
{
ObjectOutputStream oos = null;
try
{
if (IntroPlugin.getDefault() != null && IntroPlugin.getDefault().getStateLocation() != null)
{
File bundleFile = IntroPlugin.getDefault().getStateLocation().append(FEATURE_STORE_PATH).toFile();
if (!bundleFile.exists())
{
bundleFile.createNewFile();
}
IdeLog.logInfo(IntroPlugin.getDefault(), Messages.FeatureChangeManager_INF_PersistList);
oos = new ObjectOutputStream(new FileOutputStream(bundleFile));
oos.writeObject(idToVersions);
oos.flush();
}
}
catch (Exception e)
{
IdeLog.logError(IntroPlugin.getDefault(), e.getMessage());
}
finally
{
try
{
if (oos != null)
oos.close();
}
catch (IOException e)
{
// ignore
}
}
}
}