/**
* SlingBeans - NetBeans Sling plugin https://github.com/jkan997/SlingBeans
* Licensed under Apache 2.0 license http://www.apache.org/licenses/LICENSE-2.0
*/
package org.jkan997.slingbeans.slingfs;
import org.jkan997.slingbeans.helper.LogHelper;
import org.jkan997.slingbeans.helper.StringHelper;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.jkan997.slingbeans.slingfs.types.NodeType;
import org.jkan997.slingbeans.slingfs.types.NodeTypeSet;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.util.Enumerations;
/**
*
* @author jkan997
*/
public class FileObject extends org.openide.filesystems.FileObject implements SlingFileObject,Comparable {
@Override
public Map<String, FileObjectAttribute> getAttributesMap() {
return attributes;
}
@Override
public String getLocalFilePath() {
return null;
}
@Override
public int compareTo(Object o) {
FileObject f2 = (FileObject)o;
return this.getName().compareTo(f2.getName());
}
class FileObjectOutputStream2 extends ByteArrayOutputStream {
@Override
public void close() throws IOException {
super.close();
FileObject.this.setFileContent(this.toByteArray());
}
}
private FileObject jcrContent = null;
private String path = "";
private FileSystem fs;
private String name = "";
private String ext = "";
private boolean folder;
private byte[] fileContent;
private FileObject[] children = FileSystem.EMPTY_FO_ARR;
boolean childrenLoaded = false;
private long syncTimestamp = 0;
private ListenerList listeners;
private final Map<String, FileObjectAttribute> attributes = new LinkedHashMap<String, FileObjectAttribute>();
@Override
public void setAttribute(String key, Object value) throws IOException {
setAttribute(key, value, 0);
}
@Override
public void setAttribute(String key, Object value, int type) throws IOException {
LogHelper.logInfo(this, "setAttribute(%s, %s)", key, value);
FileObjectAttribute foa = null;
if (attributes.containsKey(key)) {
foa = attributes.get(key);
foa.setValue(value);
} else {
foa = new FileObjectAttribute(key, value, type);
attributes.put(key, foa);
}
foa.setModified(true);
}
@Override
public Enumeration<String> getAttributes() {
LogHelper.logInfo(this, "getAttributes()");
Enumeration<String> res = Collections.enumeration(this.attributes.keySet());
return res;
}
@Override
public FileObjectAttribute getAttribute(String key) {
FileObjectAttribute res = attributes.get(key);
LogHelper.logInfo(this, "getAttribute(%s)", key);
return res;
}
FileObject() {
}
public FileObject(FileSystem fs) {
this.fs = fs;
}
@Override
public String getName() {
return name;
}
@Override
public String getExt() {
return ext;
}
@Override
public void rename(FileLock fl, String s1, String s2) throws IOException {
LogHelper.logInfo(this, "rename(%s, %s, %s)", fl, s1, s2);
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public FileSystem getFileSystem() throws FileStateInvalidException {
LogHelper.logInfo(this, "getFileSystem()");
return fs;
}
public String getFileSystemId() {
return fs.getFileSystemId();
}
@Override
public String getPath() {
return this.path;
}
@Override
public String getFilePath() {
return getPath();
}
private String getParentPath() {
String res = StringHelper.getParentPath(path);
return res;
}
@Override
public void refresh() {
fs.getFileObject(this, true);
}
@Override
public FileObject getParent() {
String parentPath = getParentPath();
LogHelper.logInfo(this, "getParent(%s) / parentPath - %s", path, parentPath);
FileObject res = null;
if (parentPath != null) {
res = fs.getFileObject(parentPath);
}
LogHelper.logInfo(this, "Parent %s", "" + res);
return res;
}
@Override
public boolean isFolder() {
LogHelper.logInfo(this, "isFolder(%s)");
return folder;
}
public FileObject getJcrContent() {
if (!this.childrenLoaded) {
this.getChildren();
}
return jcrContent;
}
public void refreshJcrContent() {
fs.getFileObject(jcrContent, true);
}
public boolean hasContent() {
return (getJcrContent() != null);
}
public Date getCreated() {
FileObjectAttribute foa = null;
foa = getAttribute("jcr:created");
if (foa != null) {
Date created = foa.getDate();
if (created != null) {
return created;
}
}
return null;
}
@Override
public Date lastModified() {
return lastModified(true);
}
public Date lastModified(boolean forceRefresh) {
FileObjectAttribute foa = null;
Date res = new Date(2013, 0, 1);
Date created = getCreated();
if (created != null) {
res = created;
}
if (jcrContent != null) {
if (forceRefresh) {
refreshJcrContent();
}
foa = jcrContent.getAttribute("jcr:lastModified");
if (foa != null) {
Date lastModified = foa.getDate();
if (lastModified != null) {
res = lastModified;
}
}
}
LogHelper.logInfo(this, "lastModified() = %s", ("" + res));
return res;
}
@Override
public boolean isRoot() {
String parentPath = getParentPath();
boolean res = (parentPath == null);
LogHelper.logInfo(this, "parentPath() = %s", ("" + res));
return res;
}
@Override
public boolean isData() {
boolean res = !folder;
LogHelper.logInfo(this, "isData() = %s", "" + res);
return res;
}
@Override
public boolean isValid() {
LogHelper.logInfo(this, "isValid(%s)", path);
return true;
}
@Override
public void delete(FileLock fl) throws IOException {
LogHelper.logInfo(this, "delete(%s)", fl);
/* Map<String, Object> changes = new HashMap<String, Object>();
changes.put("-/" + this.getPath(),"");
fs.sendPost(changes);*/
fs.remove(this.path);
}
@Override
public final synchronized void addFileChangeListener(FileChangeListener fcl) {
if (listeners == null) {
listeners = new ListenerList<FileChangeListener>();
}
listeners.add(fcl);
}
@Override
public final synchronized void removeFileChangeListener(FileChangeListener fcl) {
if (listeners != null) {
listeners.remove(fcl);
}
}
private final Enumeration<FileChangeListener> listeners() {
if (listeners == null) {
return Enumerations.empty();
} else {
return Collections.enumeration(listeners.getAllListeners());
}
}
@Override
public long getSize() {
long res = 0;
if (fileContent != null) {
res = fileContent.length;
}
if (jcrContent != null) {
refreshJcrContent();
FileObjectAttribute foa = jcrContent.getAttribute(":jcr:data");
if (foa != null) {
Long dataSize = foa.getLong();
if (dataSize != null) {
res = dataSize;
}
}
}
LogHelper.logInfo(this, "getSize() = %s", "" + res);
return res;
}
@Override
public InputStream getInputStream() throws FileNotFoundException {
LogHelper.logInfo(this, "getInputStream()");
getFileContent();
InputStream res = null;
LogHelper.logInfo(this, "File content len %s", "" + (fileContent != null ? fileContent.length : -1));
res = new ByteArrayInputStream(fileContent);
return res;
}
public byte[] getFileContent() {
if (this.fileContent == null) {
this.fileContent = fs.getFileContent(path);
}
return fileContent;
}
public void setFileContent(byte[] fileContent) {
this.fileContent = fileContent;
fs.setFileContent(this.path, this.fileContent, false);
objectModified();
}
public void setFileContent(byte[] fileContent, boolean binary) {
this.fileContent = fileContent;
fs.setFileContent(path, fileContent, binary);
objectModified();
}
@Override
public OutputStream getOutputStream(FileLock fl) throws IOException {
LogHelper.logInfo(this, "getOutputStream()");
return new FileObjectOutputStream2();
}
@Override
public FileLock lock() throws IOException {
LogHelper.logInfo(this, "lock()");
return FileLock.NONE;
}
@Override
public void setImportant(boolean val) {
LogHelper.logInfo(this, "setImportant(%s)", "" + val);
}
@Override
public FileObject[] getChildren() {
LogHelper.logInfo(this, "getChildren() = %s elements", children.length);
if ((!childrenLoaded) && (!fs.isNoLoadMode())) {
fs.getFileObject(this.getPath(), 2);
}
childrenLoaded = true;
return children;
}
public void setChildren(List<FileObject> childrenList) {
jcrContent = null;
if (childrenList == null) {
this.children = FileSystem.EMPTY_FO_ARR;
this.childrenLoaded = false;
} else {
FileObject[] childrenArr = childrenList.toArray(FileSystem.EMPTY_FO_ARR);
boolean sortChildren = false;
if (this.getPath().length() > 0) {
sortChildren = true;
NodeTypeSet nodeTypeSet = fs.getNodeTypes();
if (nodeTypeSet != null) {
NodeType nt = nodeTypeSet.getByName(this.getPrimaryType());
if ((nt != null) && (nt.isHasOrderableChildNodes())) {
sortChildren = false;
}
}
}
if (sortChildren) {
Arrays.sort(childrenArr, FileObjectComparator.instance);
}
for (FileObject child : childrenArr) {
if (child.getName().equals("jcr:content")) {
jcrContent = child;
}
}
this.children = childrenArr;
this.childrenLoaded = true;
}
}
@Override
public FileObject getFileObject(String s1, String s2) {
LogHelper.logInfo(this, "getFileObject(%s, %s)", s1, s2);
return null;
}
@Override
public FileObject createFolder(String s1) throws IOException {
LogHelper.logInfo(this, "createFolder(%s)", s1);
return null;
}
@Override
public FileObject createData(String name, String ext) throws IOException {
LogHelper.logInfo(this, "createData(%s, %s)", name, ext);
String nodeName = null;
if ((ext != null) && (ext.length() > 0)) {
nodeName = name + "." + ext;
} else {
nodeName = name;
}
String path = this.path + "/" + nodeName;
fs.setFileContent(path, null, true);
return null;
}
public void createNode(String nodeName, String nodeType) throws IOException {
LogHelper.logInfo(this, "createNode(%s, %s)", nodeName, nodeType);
String path = this.path + "/" + nodeName;
fs.createNode(path, nodeType);
// fs.commmit();
}
public void createFile(String nodeName, byte[] content) throws IOException {
createFile(nodeName,content,null);
}
public void createFile(String nodeName, byte[] content, String mimeType) throws IOException {
LogHelper.logInfo(this, "createFile(%s, %d)", name, content.length);
String path = this.path + "/" + nodeName;
fs.createFile(path, content,mimeType);
// fs.commmit();
}
@Override
public boolean isReadOnly() {
LogHelper.logInfo(this, "isReadOnly()");
return false;
}
void setPath(String path) {
this.path = path;
}
void setName(String name) {
this.name = name;
}
void setExt(String ext) {
this.ext = ext;
}
void setFolder(boolean folder) {
this.folder = folder;
}
public String getPrimaryType() {
String res = null;
if (attributes.containsKey("jcr:primaryType")) {
res = attributes.get("jcr:primaryType").getValue().toString();
}
return res;
}
public boolean isSlingFolder() {
String primaryType = getPrimaryType();
if ((primaryType != null) && (NodeTypeSet.FOLDER_TYPES.contains(primaryType))) {
return true;
} else {
return false;
}
}
public boolean isSlingFile() {
String primaryType = getPrimaryType();
if ((primaryType != null) && (NodeTypeSet.FILE_TYPES.contains(primaryType))) {
return true;
} else {
return false;
}
}
public boolean isFile() {
this.getChildren();
return (jcrContent != null);
}
public boolean isLeafNode() {
if ((this.childrenLoaded) && (this.children.length == 0)) {
return true;
} else {
return false;
}
}
public FileObject getClassPathParent() {
FileObject parent = this;
FileObject oldParent = this;
do {
oldParent = parent;
parent = parent.getParent();
if ((parent != null) && (parent.getNameExt().equals("java"))) {
return parent;
}
} while (parent != null);
return null;
}
@Override
public synchronized void saveAttributes() {
FileObjectAttribute foa = null;
Map<String, Object> changes = new HashMap<String, Object>();
for (Map.Entry<String, FileObjectAttribute> me : attributes.entrySet()) {
foa = me.getValue();
if (foa.isRemoved()) {
String key = "-/" + path + "/" + me.getKey();
changes.put(key, null);
} else if (foa.isModified()) {
String key = path + "/" + me.getKey();
changes.put(key, foa.getValue());
}
}
fs.sendPost(changes);
for (FileObjectAttribute foa2 : attributes.values()) {
foa2.setModified(false);
}
}
@Override
public String toString() {
if ("".equals(path)) {
return "/";
}
String[] nameExt = StringHelper.extractNameExt(path);
if (nameExt[1].length() > 0) {
return nameExt[0] + "." + nameExt[1];
}
return nameExt[0];
}
public String toStringFull() {
return toStringFull(", ");
}
public String toStringFull(String separator) {
String parentPath = getParentPath();
return "FileObject{" + "path=" + path + separator + "fs=" + fs + separator + "name=" + name + separator + "ext=" + ext + separator + "folder=" + folder + separator + "parentPath=" + parentPath + separator + "fileContent=" + fileContent;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FileObject other = (FileObject) obj;
if (!Objects.equals(this.path, other.path)) {
return false;
}
return true;
}
public FileObject(FileSystem fs, boolean folder, byte[] fileContent) {
this.fs = fs;
this.folder = folder;
this.fileContent = fileContent;
}
public boolean isChildrenLoaded() {
return childrenLoaded;
}
public void setChildrenLoaded(boolean childrenLoaded) {
this.childrenLoaded = childrenLoaded;
}
public long getSyncTimestamp() {
return syncTimestamp;
}
public void objectModified() {
//syncTimestamp = System.currentTimeMillis();
//FileEvent fe = new FileEvent(this);
//this.fireFileChangedEvent(listeners(), fe);
}
}