/**
*
*/
package org.goko.core.workspace.io;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.runtime.URIUtil;
import org.goko.core.common.exception.GkException;
import org.goko.core.common.exception.GkTechnicalException;
/**
* @author PsyKo
* @date 14 mars 2016
*/
public class ProjectLocation implements IProjectLocation {
/** The name of the project */
private String name;
/** The project files by name */
private Map<String, URI> mapFile;
/** The project resource location by name */
private Map<String, URIResourceLocation> mapUriLocation;
/** The project uri */
private URI projectUri;
/** The project file URI*/
private URI projectDescriptorUri;
/** The data for the project descriptor */
private ByteBuffer projectDescriptorData;
/**
* Default constructor
*/
public ProjectLocation() {
this.name = "Untitled";
this.mapFile = new HashMap<>();
this.mapUriLocation = new HashMap<>();
}
public ProjectLocation(URI projectFileUri) {
File projectFile = new File(projectFileUri);
this.projectUri = projectFile.getParentFile().toURI();
this.name = FilenameUtils.getName(projectFile.getName());
this.projectDescriptorUri = projectFileUri;
this.mapFile = new HashMap<>();
this.mapUriLocation = new HashMap<>();
}
/**
* Constructor
*/
public ProjectLocation(URI projectUri, String name) {
this.mapFile = new HashMap<String, URI>();
this.projectUri = projectUri;
this.name = name;
this.projectDescriptorUri = new File(projectUri.toString(), name+".goko").toURI();
this.mapFile = new HashMap<>();
this.mapUriLocation = new HashMap<>();
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#getName()
*/
@Override
public String getName() {
return name;
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#setProjectDescriptor(java.net.URI)
*/
@Override
public void setProjectDescriptor(InputStream stream) throws GkException {
try {
projectDescriptorData = ByteBuffer.wrap(IOUtils.toByteArray(stream));
} catch (IOException e) {
throw new GkTechnicalException(e);
}
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#getProjectDescriptor()
*/
@Override
public InputStream getProjectDescriptor() throws GkException {
try {
return projectDescriptorUri.toURL().openStream();
} catch (IOException e) {
throw new GkTechnicalException(e);
}
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#setName(java.lang.String)
*/
@Override
public void setName(String name) {
this.name = name;
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#addResource(java.lang.String, java.io.InputStream)
*/
@Override
public IResourceLocation addResource(String name, URI uri) throws GkException {
if(!mapFile.containsKey(name)){
URI absoluteUri = uri;
if(!uri.isAbsolute()){
absoluteUri = URIUtil.makeAbsolute(uri, projectUri);
}
mapFile.put(name, absoluteUri);
mapUriLocation.put(name, new URIResourceLocation(uri, absoluteUri));
}
return mapUriLocation.get(name);
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#removeResource(java.lang.String)
*/
@Override
public void removeResource(String name) throws GkException {
if(!mapFile.containsKey(name)){
throw new GkTechnicalException("File '"+name+"' does not exist in project");
}
if(mapUriLocation.containsKey(name)){
mapUriLocation.remove(name);
}
mapFile.remove(name);
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#readResource(java.lang.String)
*/
@Override
public IResourceLocation readResource(String name) throws GkException {
if(!mapFile.containsKey(name)){
throw new GkTechnicalException("File '"+name+"' does not exist in project");
}
return mapUriLocation.get(name);
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#write()
*/
@Override
public void write() throws GkException {
try {
createProjectFolder();
File projectFolder = new File(this.projectUri);
if(!projectFolder.exists()){
// Create the project folder
projectFolder.mkdirs();
}
// Write project descriptor
File projectDescriptor = new File(projectDescriptorUri);
if(!projectDescriptor.exists()){
projectDescriptor.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(projectDescriptor);
InputStream input = new ByteArrayInputStream(projectDescriptorData.array());
IOUtils.copy(input, fileOutputStream);
input.close();
fileOutputStream.close();
} catch (IOException e) {
throw new GkTechnicalException(e);
}
}
protected void createProjectFolder(){
File projectFolder = new File(this.projectUri);
if(!projectFolder.exists()){
// Create the project folder
projectFolder.mkdirs();
}
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#importProjectDependencies()
*/
@Override
public void importProjectDependencies() throws GkException {
createProjectFolder();
// Export each URI to local folder
Set<Entry<String, URI>> entrySet = mapFile.entrySet();
for (Entry<String, URI> entry : entrySet) {
URIResourceLocation resource = mapUriLocation.get(entry.getKey());
if(resource.getReferenceCount() > 0){
if(resource.getUri().isAbsolute()){
importResource(name, resource);
}
}else{
if(!resource.getUri().isAbsolute()){
deleteResource(name, resource);
}
}
}
}
protected void importResource(String name, URIResourceLocation resource) throws GkException{
String resourceName = URIUtil.toFile(resource.getAbsoluteUri()).getName();
try {
// Copy the resource in the project folder using the resource name
if(StringUtils.isNotBlank(resourceName)){
URI projectResource = URIUtil.append(projectUri, resourceName);
File targetFile = new File(projectResource);
if(!targetFile.exists()){
targetFile.createNewFile();
}
InputStream sourceInputStream = resource.openInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
IOUtils.copy(sourceInputStream, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
sourceInputStream.close();
URI relativeUri = URIUtil.makeRelative(projectResource, projectUri);
resource.setUri(relativeUri);
mapUriLocation.remove(name);
mapUriLocation.put(resourceName, resource);
}
} catch (IOException e) {
throw new GkTechnicalException(e);
}
}
protected void deleteResource(String name, URIResourceLocation resource){
URI projectResource = URIUtil.makeAbsolute(resource.getUri(), projectUri);
File targetFile = new File(projectResource);
if(targetFile.exists() && targetFile.canWrite()){
targetFile.delete();
}
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#read()
*/
@Override
public void read() throws GkException {
readFolder(new File(projectUri));
}
protected void readFolder(File folder) throws GkException{
File[] children = folder.listFiles();
for (File file : children) {
if(file.isDirectory()){
readFolder(file);
}else{
// Make sure we don't read project file
if(!URIUtil.sameURI(projectDescriptorUri, file.toURI())){
URI relativePath = URIUtil.makeRelative(file.toURI(), projectUri);
addResource(relativePath.toString(), relativePath);
}
}
}
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#isLocationDefined()
*/
@Override
public boolean isLocationDefined() {
return projectUri != null;
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#setLocation(java.net.URI)
*/
@Override
public void setLocation(URI target) {
projectUri = target;
projectDescriptorUri = URIUtil.append(projectUri, name+".goko");
}
/** (inheritDoc)
* @see org.goko.core.workspace.io.IProjectLocation#getLocation()
*/
@Override
public URI getLocation() {
return projectUri;
}
protected URI getURI(String name){
return mapFile.get(name);
}
}