/*******************************************************************************
* Copyright (c) 2006-2008, Cloudsmith Inc.
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text of
* such license is available at www.eclipse.org.
******************************************************************************/
package org.eclipse.buckminster.p2.remote.server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import org.eclipse.buckminster.p2.remote.Activator;
import org.eclipse.buckminster.p2.remote.FacadeAlreadyExistsException;
import org.eclipse.buckminster.p2.remote.IRepositoryFacade;
import org.eclipse.buckminster.p2.remote.IRepositoryServer;
import org.eclipse.buckminster.p2.remote.NoSuchFacadeException;
import org.eclipse.buckminster.runtime.BuckminsterException;
import org.eclipse.buckminster.runtime.IOUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.equinox.internal.p2.console.ProvisioningHelper;
import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepository;
import org.eclipse.equinox.internal.provisional.p2.artifact.repository.IArtifactRepositoryManager;
import org.eclipse.equinox.internal.provisional.p2.core.ProvisionException;
import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepository;
import org.eclipse.equinox.internal.provisional.p2.metadata.repository.IMetadataRepositoryManager;
import org.jabsorb.JSONSerializer;
/**
* @author Thomas Hallgren
*/
public class RepositoryServer implements IRepositoryServer
{
private static final String PROP_METADATAREPOSITORY_PREFIX = "metadataRepository.";
private static final String PROP_ARTIFACTREPOSITORY_PREFIX = "artifactRepository.";
public static IRepositoryServer getServer(URI uri, JSONSerializer serializer) throws IOException
{
synchronized(s_servers)
{
RepositoryServer server = s_servers.get(uri);
if(server == null)
{
server = new RepositoryServer(uri, serializer);
s_servers.put(uri, server);
}
return server;
}
}
static URL url(URI uri)
{
try
{
return uri.toURL();
}
catch(MalformedURLException e)
{
throw new RuntimeException(e);
}
}
private final URI m_uri;
private final Map<String, URI> m_knownArtifactRepos = new HashMap<String, URI>();
private final Map<String, URI> m_knownMetadataRepos = new HashMap<String, URI>();
private final JSONSerializer m_serializer;
private static final Map<URI, RepositoryServer> s_servers = new HashMap<URI, RepositoryServer>();
private RepositoryServer(URI uri, JSONSerializer serializer) throws IOException
{
m_uri = uri;
m_serializer = serializer;
load();
}
public synchronized IRepositoryFacade createArtifactRepositoryFacade(String facadeName)
throws ProvisionException
{
if(m_knownArtifactRepos.containsKey(facadeName))
throw new FacadeAlreadyExistsException(m_uri, facadeName);
File facadeArea = getFacadeArea(facadeName, false);
URI repoURI = new File(facadeArea, "artifacts").toURI();
IArtifactRepository repo = Activator.getArtifactRepositoryManager().createRepository(url(repoURI),
facadeName, IArtifactRepositoryManager.TYPE_SIMPLE_REPOSITORY, null);
m_knownArtifactRepos.put(facadeName, repoURI);
try
{
save();
return new ArtifactRepositoryFacade(facadeName, new LoggingArtifactRepository(this, repo,
facadeArea));
}
catch(CoreException e)
{
throw new ProvisionException(e.getStatus());
}
}
public synchronized IRepositoryFacade createMetadataRepositoryFacade(String facadeName)
throws ProvisionException
{
if(m_knownMetadataRepos.containsKey(facadeName))
throw new FacadeAlreadyExistsException(m_uri, facadeName);
File facadeArea = getFacadeArea(facadeName, true);
URI repoURI = new File(facadeArea, "content").toURI();
IMetadataRepository repo = Activator.getMetadataRepositoryManager().createRepository(url(repoURI),
facadeName, IMetadataRepositoryManager.TYPE_SIMPLE_REPOSITORY, null);
m_knownMetadataRepos.put(facadeName, repoURI);
save();
return new MetadataRepositoryFacade(facadeName, new LoggingMetadataRepository(this, repo, facadeArea));
}
public synchronized boolean deleteArtifactRepositoryFacade(String facadeName) throws ProvisionException
{
return deleteRepositoryFacade(facadeName, m_knownArtifactRepos, false);
}
public synchronized boolean deleteMetadataRepositoryFacade(String facadeName) throws ProvisionException
{
return deleteRepositoryFacade(facadeName, m_knownMetadataRepos, true);
}
public synchronized IRepositoryFacade getArtifactRepositoryFacade(String facadeName)
throws ProvisionException
{
URI repoURI = m_knownArtifactRepos.get(facadeName);
if(repoURI == null)
throw new NoSuchFacadeException(m_uri, facadeName);
try
{
return new ArtifactRepositoryFacade(facadeName, new LoggingArtifactRepository(this,
ProvisioningHelper.getArtifactRepository(url(repoURI)), getFacadeArea(facadeName, false)));
}
catch(CoreException e)
{
throw new ProvisionException(e.getStatus());
}
}
public synchronized List<String> getArtifactRepositoryFacadeNames()
{
return getRepositoryFacadeNames(m_knownArtifactRepos);
}
public synchronized IRepositoryFacade getMetadataRepositoryFacade(String facadeName)
throws ProvisionException
{
URI repoURI = m_knownMetadataRepos.get(facadeName);
if(repoURI == null)
throw new NoSuchFacadeException(m_uri, facadeName);
return new MetadataRepositoryFacade(facadeName, new LoggingMetadataRepository(this,
ProvisioningHelper.getMetadataRepository(url(repoURI)), getFacadeArea(facadeName, true)));
}
public synchronized List<String> getMetadataRepositoryFacadeNames()
{
return getRepositoryFacadeNames(m_knownMetadataRepos);
}
public JSONSerializer getSerializer()
{
return m_serializer;
}
public void hardReset() throws ProvisionException
{
synchronized(s_servers)
{
deleteRecursive(Activator.getAgentLocation());
s_servers.clear();
m_knownArtifactRepos.clear();
m_knownMetadataRepos.clear();
s_servers.put(m_uri, this);
}
}
private void deleteRecursive(File file)
{
File[] subfiles = file.listFiles();
if(subfiles != null)
for(File subfile : subfiles)
deleteRecursive(subfile);
file.delete();
}
private boolean deleteRepositoryFacade(String facadeName, Map<String, URI> knownRepos, boolean isMetadata)
throws ProvisionException
{
URI repoURI = knownRepos.get(facadeName);
if(repoURI == null)
return false;
if(isMetadata)
Activator.getMetadataRepositoryManager().removeRepository(url(repoURI));
else
Activator.getArtifactRepositoryManager().removeRepository(url(repoURI));
deleteRecursive(getFacadeArea(facadeName, isMetadata));
try
{
knownRepos.remove(facadeName);
save();
}
catch(CoreException e)
{
throw new ProvisionException(e.getStatus());
}
return true;
}
private File getFacadeArea(String facadeName, boolean isMetadata)
{
return new File(new File(Activator.getAgentLocation(), isMetadata ? "metadata" : "artifact"),
facadeName);
}
private List<String> getRepositoryFacadeNames(Map<String, URI> knownRepos)
{
ArrayList<String> names = new ArrayList<String>(knownRepos.keySet());
Collections.sort(names);
return names;
}
private File getStateFile()
{
File repoArea = Activator.getAgentLocation();
byte[] repoIDBytes;
try
{
repoIDBytes = m_uri.toASCIIString().getBytes("US-ASCII");
}
catch(UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
UUID repoID = UUID.nameUUIDFromBytes(repoIDBytes);
return new File(repoArea, repoID.toString());
}
private void load() throws IOException
{
Properties props = new Properties();
InputStream input = null;
try
{
input = new BufferedInputStream(new FileInputStream(getStateFile()));
props.load(input);
}
catch(FileNotFoundException e)
{
}
finally
{
IOUtils.close(input);
}
Enumeration<?> names = props.propertyNames();
while(names.hasMoreElements())
{
String propName = (String)names.nextElement();
boolean isMeta = propName.startsWith(PROP_METADATAREPOSITORY_PREFIX);
if(!(isMeta || propName.startsWith(PROP_ARTIFACTREPOSITORY_PREFIX)))
continue;
String repoURI = props.getProperty(propName);
if(repoURI == null)
continue;
URI uri;
try
{
uri = new URI(repoURI);
}
catch(URISyntaxException e)
{
e.printStackTrace();
continue;
}
if(isMeta)
m_knownMetadataRepos.put(propName.substring(PROP_METADATAREPOSITORY_PREFIX.length()), uri);
else
m_knownArtifactRepos.put(propName.substring(PROP_ARTIFACTREPOSITORY_PREFIX.length()), uri);
}
}
private void save() throws ProvisionException
{
Properties props = new Properties();
for(Map.Entry<String, URI> entry : m_knownMetadataRepos.entrySet())
props.setProperty(PROP_METADATAREPOSITORY_PREFIX + entry.getKey(), entry.getValue().toString());
for(Map.Entry<String, URI> entry : m_knownArtifactRepos.entrySet())
props.setProperty(PROP_ARTIFACTREPOSITORY_PREFIX + entry.getKey(), entry.getValue().toString());
OutputStream output = null;
try
{
output = new BufferedOutputStream(new FileOutputStream(getStateFile()));
props.store(output, null);
}
catch(IOException e)
{
throw new ProvisionException(BuckminsterException.createStatus(e));
}
finally
{
IOUtils.close(output);
}
}
}