blob: 843f498cea1e41f8c6b326dd1a462d18a3e638c6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2018 Sonatype, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Sonatype, Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.m2e.core.internal.project.registry;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Version;
import org.osgi.service.packageadmin.PackageAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.osgi.service.resolver.VersionRange;
import org.codehaus.plexus.util.IOUtil;
import org.eclipse.m2e.core.internal.MavenPluginActivator;
/**
* Workspace state reader
*
* @author Eugene Kuleshov
*/
public class ProjectRegistryReader {
private static final Logger log = LoggerFactory.getLogger(ProjectRegistryReader.class);
private static final String WORKSPACE_STATE = "workspaceState.ser"; //$NON-NLS-1$
private final File stateFile;
private static PackageAdmin packageAdmin;
public ProjectRegistryReader(File stateLocationDir) {
this.stateFile = new File(stateLocationDir, WORKSPACE_STATE);
}
public ProjectRegistry readWorkspaceState(final ProjectRegistryManager managerImpl) {
if(stateFile.exists()) {
final PackageAdmin packageAdmin = getPackageAdmin();
ObjectInputStream is = null;
try {
is = new ObjectInputStream(new BufferedInputStream(new FileInputStream(stateFile))) {
{
enableResolveObject(true);
}
protected Object resolveObject(Object o) throws IOException {
if(o instanceof IPathReplace) {
return ((IPathReplace) o).getPath();
} else if(o instanceof IFileReplace) {
return ((IFileReplace) o).getFile();
} else if(o instanceof MavenProjectManagerImplReplace) {
return managerImpl;
}
return super.resolveObject(o);
}
protected java.lang.Class<?> resolveClass(java.io.ObjectStreamClass desc) throws IOException,
ClassNotFoundException {
String symbolicName = (String) readObject();
if(symbolicName == null) {
return super.resolveClass(desc);
}
String versionStr = (String) readObject();
Version version = Version.parseVersion(versionStr);
VersionRange versionRange = new VersionRange(version, true, version, true);
Bundle[] bundles = packageAdmin.getBundles(symbolicName, versionRange.toString());
if(bundles == null || bundles.length != 1) {
throw new ClassNotFoundException("Could not find bundle " + symbolicName + "/" + version //$NON-NLS-1$ //$NON-NLS-2$
+ " required to load class " + desc.getName()); //$NON-NLS-1$
}
return bundles[0].loadClass(desc.getName());
};
};
return (ProjectRegistry) is.readObject();
} catch(Exception ex) {
log.error("Can't read workspace state", ex);
} finally {
IOUtil.close(is);
}
}
return null;
}
private static synchronized PackageAdmin getPackageAdmin() {
// TODO inject dependencies already!
if(packageAdmin == null) {
BundleContext context = MavenPluginActivator.getDefault().getBundleContext();
ServiceReference<PackageAdmin> serviceReference = context.getServiceReference(PackageAdmin.class);
packageAdmin = context.getService(serviceReference);
}
return packageAdmin;
}
public void writeWorkspaceState(ProjectRegistry state) {
final ClassLoader thisClassloader = getClass().getClassLoader();
ObjectOutputStream os = null;
try {
os = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(stateFile))) {
{
enableReplaceObject(true);
}
protected Object replaceObject(Object o) throws IOException {
if(o instanceof IPath) {
return new IPathReplace((IPath) o);
} else if(o instanceof IFile) {
return new IFileReplace((IFile) o);
} else if(o instanceof ProjectRegistryManager) {
return new MavenProjectManagerImplReplace();
}
return super.replaceObject(o);
}
protected void annotateClass(java.lang.Class<?> cl) throws IOException {
// if the class is visible through this classloader, assume it will be during reading stream back
try {
Class<?> target = cl;
while(target.isArray()) {
target = target.getComponentType();
}
if(target.isPrimitive() || target.equals(thisClassloader.loadClass(target.getName()))) {
writeObject(null); // TODO is there a better way?
return;
}
} catch(ClassNotFoundException ex) {
// fall through
}
// foreign class
Bundle bundle = FrameworkUtil.getBundle(cl);
if(bundle != null) {
writeObject(bundle.getSymbolicName());
writeObject(bundle.getVersion().toString());
}
// TODO this will likely fail during desirialization
};
};
synchronized(state) { // see MNGECLIPSE-860
os.writeObject(state);
}
} catch(Exception ex) {
log.error("Can't write workspace state", ex);
} finally {
IOUtil.close(os);
}
}
/**
* IPath replacement used for object serialization
*/
private static final class IPathReplace implements Serializable {
private static final long serialVersionUID = -2361259525684491181L;
private final String path;
public IPathReplace(IPath path) {
this.path = path.toPortableString();
}
public IPath getPath() {
return Path.fromPortableString(path);
}
}
/**
* IFile replacement used for object serialization
*/
private static final class IFileReplace implements Serializable {
private static final long serialVersionUID = -7266001068347075329L;
private final String path;
public IFileReplace(IFile file) {
this.path = file.getFullPath().toPortableString();
}
public IFile getFile() {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
return root.getFile(Path.fromPortableString(path));
}
}
static final class MavenProjectManagerImplReplace implements Serializable {
private static final long serialVersionUID = 1995671440438776471L;
}
}