/*******************************************************************************
* Copyright © 2011, 2013 IBM Corporation and others.
* 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.ide.core.internal.builder;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.edt.compiler.internal.core.builder.BuildException;
import org.eclipse.edt.compiler.tools.EGL2IR;
import org.eclipse.edt.mof.EObject;
import org.eclipse.edt.mof.egl.Type;
import org.eclipse.edt.mof.serialization.AbstractObjectStore;
import org.eclipse.edt.mof.serialization.CachingObjectStore;
import org.eclipse.edt.mof.serialization.DeserializationException;
import org.eclipse.edt.mof.serialization.Deserializer;
import org.eclipse.edt.mof.serialization.IEnvironment;
import org.eclipse.edt.mof.serialization.ObjectStore;
import org.eclipse.edt.mof.serialization.SerializationException;
import org.eclipse.edt.mof.serialization.ZipFileObjectStore;
public class IFileSystemObjectStore extends AbstractObjectStore implements CachingObjectStore {
private static final boolean DEBUG = false;
private Map<String,EObject> cache;
IPath root;
String fileExtension;
public IFileSystemObjectStore(IPath root, IEnvironment env) {
super(env);
this.root = root;
this.cache = new HashMap<String, EObject>();
}
public IFileSystemObjectStore(IPath root, IEnvironment env, String storageFormat) {
this(root, env, storageFormat, ObjectStore.XML.equals(storageFormat) ? ZipFileObjectStore.MOFXML : ZipFileObjectStore.MOFBIN);
}
public IFileSystemObjectStore(IPath root, IEnvironment env, String storageFormat, String fileExtension) {
super(env, storageFormat, EGL2IR.EGLXML.equals(fileExtension) ? Type.EGL_KeyScheme : ObjectStore.DefaultScheme);
this.root = root;
this.fileExtension = fileExtension;
this.cache = new HashMap<String, EObject>();
}
public Deserializer createDeserializer(String typeSignature) {
try {
IPath path = root.append(typeSignature.toUpperCase().toLowerCase().replace('.', '/') + getFileExtension());
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
if (file.exists()) {
BufferedInputStream inputStream;
try {
inputStream = new BufferedInputStream(file.getContents());
return factory.createDeserializer(inputStream, env);
}
catch(CoreException e) {
throw new BuildException("CoreException", e); //$NON-NLS-1$
}
}
}
catch(Exception e) {
}
return null;
}
@Override
public void primRemove(String key) {
// key already has the scheme removed
String normKey = key.toUpperCase().toLowerCase();
cache.remove(normKey);
}
@Override
public void put(String key, EObject obj) throws SerializationException {
super.put(key, obj);
if (obj != null) {
String normKey = removeSchemeFromKey(key).toUpperCase().toLowerCase();
cache.put(normKey, obj);
}
}
@Override
public void store(String typeSignature, Object obj) {
if (!(obj instanceof byte[])) {
throw new IllegalArgumentException("Object not of type: byte[]");
}
byte[] entry = (byte[])obj;
InputStream inputStream = new BufferedInputStream(new ByteArrayInputStream(entry));
try {
IFile file = getOutputFileForWrite(typeSignature);
if (file.exists()) {
// Deal with shared output folders... last one wins... no collision cases detected
if (DEBUG) {
System.out.println("Writing changed file " + file.getName());//$NON-NLS-1$
}
if (entry.length > 0) {
file.setContents(inputStream, true, false, null);
if (!file.isDerived()) {
file.setDerived(true, null);
}
}
else {
file.delete(true,null);
}
}
else if (entry.length > 0) {
// Default implementation just writes out the bytes for the new build file...
if(DEBUG){
System.out.println("Writing new file " + file.getName());//$NON-NLS-1$
}
file.create(inputStream, IResource.FORCE, null);
file.setDerived(true, null);
}
}
catch(CoreException e) {
throw new SerializationException(e);
}
finally {
try {
inputStream.close();
}
catch(IOException e) {
throw new SerializationException(e);
}
}
}
private IFile getOutputFileForWrite(String typeSignature) throws CoreException {
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
String relativeFilePath = typeSignature.replace('.', '/') + getFileExtension();
int lastSlash = relativeFilePath.lastIndexOf( '/' );
if ( lastSlash != -1 )
{
// Make sure parent folders are created.
Util.createFolder(new Path(relativeFilePath.substring(0, lastSlash)), workspaceRoot.getFolder(root));
}
return workspaceRoot.getFile(root.append(relativeFilePath));
}
@Override
public boolean containsKey(String key) {
key = removeSchemeFromKey(key);
IPath path = root.append(key.replace('.', '/') + getFileExtension());
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
return file.exists();
}
@Override
public long lastModified(String key) {
key = removeSchemeFromKey(key);
IPath path = root.append(key.replace('.', '/') + getFileExtension());
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
return file.getModificationStamp();
}
public String getFileExtension() {
if (fileExtension == null) {
fileExtension = BINARY.equals(storageFormat) ? ZipFileObjectStore.MOFBIN : ZipFileObjectStore.MOFXML;
}
return fileExtension;
}
@Override
public EObject get(String key) throws DeserializationException {
String normKey = removeSchemeFromKey(key).toUpperCase().toLowerCase();
EObject value = cache.get(normKey);
if (value == null) {
value = super.get(key);
if (value != null) {
cache.put(normKey, value);
}
}
return value;
}
@Override
public EObject getFromCache(String key) {
String normKey = removeSchemeFromKey(key).toUpperCase().toLowerCase();
return cache.get(normKey);
}
@Override
public void addToCache(String key, EObject object) {
String normKey = removeSchemeFromKey(key).toUpperCase().toLowerCase();
cache.put(normKey, object);
}
@Override
public void clearCache() {
cache.clear();
}
public List<String> getAllKeysFromPkg(String pkg, boolean includeSubPkgs) {
if (!containsPkg(pkg)) {
return new ArrayList<String>();
}
IPath path = root.append(pkg.replace('.', '/'));
IFolder pkgDir = ResourcesPlugin.getWorkspace().getRoot().getFolder(path);
return getAllKeysFromPkg(pkgDir, pkg, includeSubPkgs);
}
private List<String> getAllKeysFromPkg(final IFolder pkgDir, final String pkg, final boolean includeSubPkgs) {
final List<String> list = new ArrayList<String>();
try {
pkgDir.accept(new IResourceVisitor() {
@Override
public boolean visit(IResource resource) throws CoreException {
if (resource.equals(pkgDir)) {
return true;
}
if (resource.getType() == IResource.FOLDER) {
if (includeSubPkgs) {
String subPkgName;
if (pkg.length() > 0) {
subPkgName = pkg + "." + resource.getName();
}
else {
subPkgName = resource.getName();
}
list.addAll(getAllKeysFromPkg((IFolder)resource, subPkgName, includeSubPkgs));
}
}
else {
if (resource.getType() == IResource.FILE) {
if (getFileExtension().equals(getFileExtension((IFile)resource))) {
if (pkg.length() > 0)
list.add(getScheme() + pkg + "." + getFileName((IFile)resource));
else
list.add(getScheme() + getFileName((IFile)resource));
}
}
}
return false;
}
});
} catch (CoreException e) {
e.printStackTrace();
}
return list;
}
private String getFileExtension(IFile file) {
String name = file.getName();
int index = name.lastIndexOf(".");
if (index < 0) {
return null;
}
return name.substring(index);
}
private String getFileName(IResource file) {
String name = file.getName();
int index = name.lastIndexOf(".");
if (index < 0) {
return name;
}
return name.substring(0, index);
}
private boolean containsPkg(String pkg) {
IPath path = root.append(pkg.replace('.', '/'));
IFolder folder = ResourcesPlugin.getWorkspace().getRoot().getFolder(path);
return folder.exists();
}
private String getScheme() {
if (getFileExtension().equals(ZipFileObjectStore.MOFBIN) || getFileExtension().equals(ZipFileObjectStore.MOFXML)) {
return "";
}
else {
return "egl:";
}
}
@Override
public String toString() {
// For easier debugging.
return "IFileSystemObjectStore root=" + root + " scheme=" + getScheme();
}
}