/*******************************************************************************
* Signavio Core Components
* Copyright (C) 2012 Signavio GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package com.signavio.warehouse.directory.business;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.json.JSONException;
import org.oryxeditor.server.diagram.basic.BasicDiagramBuilder;
import org.oryxeditor.server.diagram.generic.GenericDiagram;
import com.signavio.platform.security.business.FsSecureBusinessObject;
import com.signavio.platform.security.business.util.UUID;
import com.signavio.platform.util.fsbackend.FileSystemUtil;
import com.signavio.warehouse.business.FsEntityManager;
import com.signavio.warehouse.model.business.FsModel;
import com.signavio.warehouse.model.business.ModelType;
import com.signavio.warehouse.model.business.ModelTypeManager;
/**
* Implementation of a directory in the file accessing Oryx backend.
*
* TODO : Auto renameof new model, directory ?
*
* @author Stefan Krumnow
*
*/
public class FsDirectory extends FsSecureBusinessObject {
// Members
protected String path;
// private String name;
/**
* Constructor
*
* Constructs a new directory object for an EXISTING filesystem directory.
*
* @param parentDirectory
* @param name
*/
public FsDirectory(String path) {
if (!FileSystemUtil.isFileDirectory(path)){
throw new IllegalStateException("Path does not point to a directory.");
} else if ( ! FileSystemUtil.isFileExistent(path) || ! FileSystemUtil.isFileAccessible(path)){
throw new IllegalStateException("Directory can not be accessed");
}
this.path = path;
}
public String getName() {
return getDirName();
}
public String getDescription() {
return "";
}
public Date getCreationDate() {
return new Date();
}
public void setName(String name) {
name = FileSystemUtil.getCleanFileName(name);
if (name.equals(getName())) {
return ;
}
String newName = getPathPrefix() + File.separator + name;
if (FileSystemUtil.renameFile(getPath(), newName)){
this.path = newName;
} else {
throw new IllegalArgumentException("Cannot rename directory");
}
}
public void setDescription(String description) {
return ;
}
public void setCreationDate() {
return ;
}
public Set<FsDirectory> getChildDirectories(){
Set<FsDirectory> childDirectories = new HashSet<FsDirectory>();
File[] children = FileSystemUtil.getFileChildren(getPath(), null);
if (children == null) {
return childDirectories;
}
for (File f : children){
if (f.isDirectory()) {
childDirectories.add(new FsDirectory(f.getAbsolutePath()));
}
}
return childDirectories;
}
public Set<FsModel> getChildModels() {
Set<FsModel> childModels = new HashSet<FsModel>();
File[] children = FileSystemUtil.getFileChildren(getPath(), ModelTypeManager.getInstance().getFilenameFilter());
if (children == null) {
return childModels;
}
for (File f : children){
if (f.isFile()) {
childModels.add(new FsModel(f.getAbsolutePath()));
}
}
return childModels;
}
public FsDirectory getParentDirectory() {
File rootDir = new File(FsRootDirectory.getSingleton().getPath());
File parentDir = new File(getPathPrefix());
try {
if (rootDir.getCanonicalPath().equals(parentDir.getCanonicalPath())){
return FsRootDirectory.getSingleton();
}
} catch (IOException e) {
throw new IllegalArgumentException("Cannot determine canonical path.", e);
}
return new FsDirectory(getPathPrefix());
}
public void addChildDirectory(FsDirectory dir) {
dir.moveTo(this);
}
public FsDirectory createDirectory(String name, String description) {
name = FileSystemUtil.getCleanFileName(name);
String path = getPath() + File.separator + name;
File f = new File (path);
if (f.exists()) {
throw new IllegalArgumentException("Name already exists.");
}
if ( FileSystemUtil.createDirectory(path) != null ) {
return new FsDirectory(path);
} else {
throw new IllegalArgumentException("Could not create Directory");
}
}
public void addChildModel(FsModel model) throws UnsupportedEncodingException, JSONException {
model.moveTo(this);
}
public FsModel createModel(String name, String description, String type, String jsonRep, String svgRep, String comment) {
return createModel(UUID.getUUID().toString(), name, description, type, jsonRep, svgRep, comment);
}
public FsModel createModel(String id, String name, String description, String type, String jsonRep, String svgRep, String comment) {
name = FileSystemUtil.getCleanFileName(name);
String namespace;
try {
GenericDiagram diagram = BasicDiagramBuilder.parseJson(jsonRep);
namespace = diagram.getStencilsetRef().getNamespace();
} catch (JSONException e) {
throw new IllegalStateException("Could not create new model", e);
}
ModelType modelType = ModelTypeManager.getInstance().getModelType(namespace);
String path = getPath() + File.separator + name + modelType.getFileExtension();
File f = new File (path);
if (f.exists()) {
throw new IllegalArgumentException("Name already exists.");
}
modelType.storeModel(path, id, namespace, description, type, jsonRep, svgRep);
return new FsModel(getPath(), name, modelType.getFileExtension());
}
public void delete() {
for (FsModel child : getChildModels()) {
child.delete();
}
for (FsDirectory child : getChildDirectories()) {
child.delete();
}
FileSystemUtil.deleteFileOrDirectory(getPath());
}
public void search(final String searchTerm, List<FsSecureBusinessObject> result) {
// Find Models
FilenameFilter modelFilter = new FilenameFilter(){
public boolean accept(File dir, String name) {
String[] nameAndExtension = ModelTypeManager.splitNameAndExtension(name);
if (nameAndExtension == null || nameAndExtension.length < 2){
return false;
}
return ModelTypeManager.getInstance().getFilenameFilter().accept(dir, name) &&
nameAndExtension[0].toLowerCase().contains(searchTerm.toLowerCase());
}
};
File[] children = FileSystemUtil.getFileChildren(getPath(), modelFilter);
if (children != null) {
for (File f : children){
if (f.isFile()) {
result.add(new FsModel(f.getAbsolutePath()));
}
}
}
// Find Directories
FilenameFilter dirFilter = new FilenameFilter(){
public boolean accept(File dir, String name) {
return name.toLowerCase().contains(searchTerm.toLowerCase());
}
};
File[] dirChildren = FileSystemUtil.getFileChildren(getPath(), dirFilter);
if (dirChildren != null) {
for (File f : dirChildren){
if (f.isDirectory()) {
result.add(new FsDirectory(f.getAbsolutePath()));
}
}
}
// Visit Child Directories
for (FsDirectory child : getChildDirectories()){
child.search(searchTerm, result);
}
}
/*
*
* Private Functions
*
*/
public String getPath(){
return path;
}
private String getDirName(){
if (path.contains(File.separator)){
int i = path.lastIndexOf(File.separator);
return path.substring(i+1);
} else {
throw new IllegalStateException("Path cannot be resolved.");
}
}
private String getPathPrefix() {
if (path.contains(File.separator)){
int i = path.lastIndexOf(File.separator);
return path.substring(0, i);
} else {
throw new IllegalStateException("Path cannot be resolved.");
}
}
private void moveTo(FsDirectory newParent) {
if (newParent.equals(getParentDirectory())) {
return ;
}
String dirName = getName();
if (!FileSystemUtil.renameFile(getPath(), newParent.getPath() + File.separator + dirName)){
throw new IllegalArgumentException("Cannot move directory");
}
}
/*
*
* INTERFACE COMPLIANCE METHODS
*
*/
@Override
public boolean equals(Object o){
if (o instanceof FsDirectory){
FsDirectory d = (FsDirectory)o;
return getPath().equals(d.getPath());
}
return false;
}
public Set<FsDirectory> getChildDirectoriesByPrivileges(Set<String> privileges) {
return getChildDirectories();
}
@Override
@SuppressWarnings("unchecked")
public <T extends FsSecureBusinessObject> Set<T> getChildren(Class<T> type) {
if (FsModel.class.isAssignableFrom(type)){
return (Set<T>) getChildModels();
} else if (FsDirectory.class.isAssignableFrom(type)){
return (Set<T>) getChildDirectories();
} else {
return super.getChildren(type);
}
}
@Override
@SuppressWarnings("unchecked")
public <T extends FsSecureBusinessObject> Set<T> getParents(Class<T> businessObjectClass) {
if (FsDirectory.class.isAssignableFrom(businessObjectClass)){
Set<T> parentDirectories = new HashSet<T>(1);
FsDirectory parentDirectory = getParentDirectory();
if (parentDirectory != null){
parentDirectories.add((T)parentDirectories);
}
return parentDirectories;
} else if (FsEntityManager.class.isAssignableFrom(businessObjectClass)){
return (Set<T>)FsEntityManager.getSingletonSet();
} else {
return super.getParents(businessObjectClass);
}
}
@Override
public String getId() {
String path = getPath();
String rootPath = FsRootDirectory.getSingleton().getPath() + File.separator;
if (path.startsWith(rootPath)){
path = FsRootDirectory.ID_OF_SINGLETON + File.separator + path.substring(rootPath.length());
}
path = path.replace(File.separator, ";");
return path;
}
public List<FsDirectory> getParentDirectories() {
List<FsDirectory> parents = new ArrayList<FsDirectory>();
FsDirectory parent = getParentDirectory();
if(parent != null) {
parents.add(parent);
parents.addAll(parent.getParentDirectories());
}
return parents;
}
}