blob: 6fa30c1d8e438e66cfd1debc99b0a40f73182a06 [file] [log] [blame]
/*
* Copyright (c) 2014, 2015 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.targlets.internal.core;
import org.eclipse.oomph.p2.core.AgentManager;
import org.eclipse.oomph.p2.core.BundlePool;
import org.eclipse.oomph.p2.core.P2Util;
import org.eclipse.oomph.p2.core.Profile;
import org.eclipse.oomph.p2.core.ProfileCreator;
import org.eclipse.oomph.targlets.core.ITargletContainerDescriptor;
import org.eclipse.oomph.targlets.core.WorkspaceIUInfo;
import org.eclipse.oomph.util.IORuntimeException;
import org.eclipse.oomph.util.IOUtil;
import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl.EObjectInputStream;
import org.eclipse.emf.ecore.resource.impl.BinaryResourceImpl.EObjectOutputStream;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.engine.IProfile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
/**
* @author Eike Stepper
*/
public final class TargletContainerDescriptor implements ITargletContainerDescriptor, Comparable<TargletContainerDescriptor>
{
public static final String PROP_TARGLET_CONTAINER_WORKSPACE = "targlet.container.workspace"; //$NON-NLS-1$
public static final String PROP_TARGLET_CONTAINER_ID = "targlet.container.id"; //$NON-NLS-1$
public static final String PROP_TARGLET_CONTAINER_DIGEST = "targlet.container.digest"; //$NON-NLS-1$
@SuppressWarnings("restriction")
private static final IPath INSTALL_FOLDERS = org.eclipse.pde.internal.core.PDECore.getDefault().getStateLocation().append(".install_folders");
private static final File DEFAULT_INSTALL_FOLDER = INSTALL_FOLDERS.append("default").toFile();
private static long lastStamp;
private String id;
private File poolLocation;
private String workingDigest;
private Collection<WorkspaceIUInfo> workingProjects;
private UpdateProblem updateProblem;
private transient BundlePool bundlePool;
private transient Profile transactionProfile;
private transient Runnable restoreBundlePoolTimestamps;
public TargletContainerDescriptor()
{
}
public TargletContainerDescriptor(String id, File poolLocation)
{
this.id = id;
this.poolLocation = poolLocation;
}
public TargletContainerDescriptor(EObjectInputStream stream) throws IOException
{
id = stream.readString();
String path = stream.readString();
if (path != null)
{
poolLocation = new File(path);
}
workingDigest = stream.readString();
int size = stream.readInt();
if (size != 0)
{
workingProjects = new ArrayList<WorkspaceIUInfo>();
for (int i = 0; i < size; i++)
{
WorkspaceIUInfo workspaceIUInfo = new WorkspaceIUInfo(stream);
workingProjects.add(workspaceIUInfo);
}
}
size = stream.readInt();
if (size != 0)
{
byte[] bytes = new byte[size];
for (int i = 0; i < size; i++)
{
bytes[i] = stream.readByte();
}
try
{
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
updateProblem = (UpdateProblem)new ObjectInputStream(bais).readObject();
}
catch (ClassNotFoundException ex)
{
throw new IORuntimeException(ex);
}
}
}
public void write(EObjectOutputStream stream) throws IOException
{
stream.writeString(id);
stream.writeString(poolLocation == null ? null : poolLocation.getAbsolutePath());
stream.writeString(workingDigest);
int size = workingProjects == null ? 0 : workingProjects.size();
stream.writeInt(size);
if (size != 0)
{
for (WorkspaceIUInfo workspaceIUInfo : workingProjects)
{
workspaceIUInfo.write(stream);
}
}
if (updateProblem != null)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(updateProblem);
oos.close();
byte[] bytes = baos.toByteArray();
stream.writeInt(bytes.length);
for (int i = 0; i < bytes.length; i++)
{
byte b = bytes[i];
stream.writeByte(b);
}
}
else
{
stream.writeInt(0);
}
}
public String getID()
{
return id;
}
public File getPoolLocation()
{
return poolLocation;
}
public File getInstallLocation()
{
Profile workingProfile = getWorkingProfile();
if (workingProfile != null)
{
String installFolder = workingProfile.getProperty(IProfile.PROP_INSTALL_FOLDER);
if (installFolder != null)
{
return new File(installFolder);
}
}
return DEFAULT_INSTALL_FOLDER;
}
public String getWorkingDigest()
{
return workingDigest;
}
public Collection<WorkspaceIUInfo> getWorkingProjects()
{
return workingProjects;
}
public UpdateProblem getUpdateProblem()
{
return updateProblem;
}
public synchronized BundlePool getBundlePool()
{
if (bundlePool == null)
{
AgentManager agentManager = P2Util.getAgentManager();
bundlePool = agentManager.getBundlePool(poolLocation);
}
return bundlePool;
}
public int compareTo(TargletContainerDescriptor o)
{
return id.compareTo(o.getID());
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + (id == null ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
TargletContainerDescriptor other = (TargletContainerDescriptor)obj;
if (id == null)
{
if (other.id != null)
{
return false;
}
}
else if (!id.equals(other.id))
{
return false;
}
return true;
}
@Override
public String toString()
{
return MessageFormat.format("TargletContainerDescriptor[id={0}, workingDigest={1}]", id, workingDigest);
}
Profile startUpdateTransaction(String environmentProperties, String nlProperty, String digest, IProgressMonitor monitor) throws CoreException
{
if (transactionProfile != null)
{
throw new ProvisionException("An update transaction is already ongoing");
}
transactionProfile = getOrCreateProfile(id, poolLocation, environmentProperties, nlProperty, digest, monitor);
restoreBundlePoolTimestamps = P2Util.preserveBundlePoolTimestamps(poolLocation);
return transactionProfile;
}
void commitUpdateTransaction(String digest, Collection<WorkspaceIUInfo> workspaceIUInfos, IProgressMonitor monitor) throws CoreException
{
if (transactionProfile == null)
{
throw new ProvisionException("No update transaction is ongoing");
}
if (restoreBundlePoolTimestamps != null)
{
restoreBundlePoolTimestamps.run();
restoreBundlePoolTimestamps = null;
}
transactionProfile = null;
workingDigest = digest;
workingProjects = workspaceIUInfos;
resetUpdateProblem();
saveDescriptors(monitor);
}
void rollbackUpdateTransaction(Throwable t, IProgressMonitor monitor) throws CoreException
{
if (restoreBundlePoolTimestamps != null)
{
restoreBundlePoolTimestamps.run();
restoreBundlePoolTimestamps = null;
}
transactionProfile = null;
if (t != null)
{
updateProblem = UpdateProblem.create(t);
saveDescriptors(monitor);
}
}
void resetUpdateProblem()
{
updateProblem = null;
}
public String getWorkingProfileID()
{
if (workingDigest == null)
{
return null;
}
return getProfileID(workingDigest);
}
public Profile getWorkingProfile()
{
String profileID = getWorkingProfileID();
if (profileID == null)
{
return null;
}
BundlePool bundlePool = getBundlePool();
if (bundlePool == null)
{
return null;
}
return bundlePool.getProfile(profileID);
}
private Profile getOrCreateProfile(String id, File poolLocation, String environmentProperties, String nlProperty, String digest, IProgressMonitor monitor)
throws CoreException
{
AgentManager agentManager = P2Util.getAgentManager();
BundlePool bundlePool = agentManager.getBundlePool(poolLocation);
String profileID = getProfileID(digest);
Profile profile = bundlePool.getProfile(profileID);
if (profile != null)
{
File installFolder = profile.getInstallFolder();
if (installFolder == null)
{
// TODO Remove this code after a while (install folder property is set for all profiles below).
profile.delete(true);
profile = null;
}
}
if (profile == null)
{
ProfileCreator creator = bundlePool.addProfile(profileID, Profile.TYPE_TARGLET);
creator.set(PROP_TARGLET_CONTAINER_WORKSPACE, TargletContainerDescriptorManager.WORKSPACE_LOCATION);
creator.set(PROP_TARGLET_CONTAINER_ID, id);
creator.set(PROP_TARGLET_CONTAINER_DIGEST, digest);
creator.set(IProfile.PROP_INSTALL_FOLDER, INSTALL_FOLDERS.append(Long.toString(nextTimeStamp())).toOSString());
creator.setEnvironments(environmentProperties);
creator.setLanguages(nlProperty);
creator.setInstallFeatures(true);
creator.setReferencer(TargletContainerDescriptorManager.WORKSPACE_REFERENCER_FILE);
profile = creator.create();
}
return profile;
}
private static String getProfileID(String suffix)
{
return IOUtil.encodeFileName(TargletContainerDescriptorManager.WORKSPACE_LOCATION + "-" + suffix);
}
private static void saveDescriptors(IProgressMonitor monitor) throws CoreException
{
TargletContainerDescriptorManager manager = TargletContainerDescriptorManager.getInstance();
manager.saveDescriptors(monitor);
}
private static synchronized long nextTimeStamp()
{
long stamp = System.currentTimeMillis();
if (stamp == lastStamp)
{
stamp++;
}
lastStamp = stamp;
return stamp;
}
}