public abstract class ConnectionPool {

	public abstract Connection getConnection() throws SQLException;

} public class ConnectionPoolFactory {
	private static final Logger logger = Logger.getLogger(ConnectionPoolFactory.class.getName());

	public static ConnectionPool getConnectionPool(String datasource) throws DAOConfigurationException {

		if ("postgresql".equalsIgnoreCase(datasource)) {
			// Obtain info
			String host = Config.getPostgresqlHost();
			Integer port = Config.getPostgresqlPort();
			String database = Config.getPostgresqlDatabase();
			String password = Config.getPostgresqlPassword();
			String username = Config.getPostgresqlUsername();
			int initialConns = Config.getPostgresqlInitialConns();
			int maxConns = Config.getPostgresqlMaxConns();

			//
			return new PostgresqlConnectionPool(host, port, database, username, password, initialConns, maxConns);
		}

		logger.error("Could not find any driver matching your request");
		throw new DAOConfigurationException("Driver not found");

	}
} public class DAOFactory {

	private String type;

	public DAOFactory(String type) {
		this.type = type;
	}

	public WorkspaceDAO getWorkspaceDao(Connection connection) {
		return new PostgresqlWorkspaceDAO(connection);
	}

	public UserDAO getUserDao(Connection connection) {
		return new PostgresqlUserDAO(connection);
	}

	public ItemDAO getItemDAO(Connection connection) {
		return new PostgresqlItemDAO(connection);
	}

	public ItemVersionDAO getItemVersionDAO(Connection connection) {
		return new PostgresqlItemVersionDao(connection);
	}

	public DeviceDAO getDeviceDAO(Connection connection) {
		return new PostgresqlDeviceDAO(connection);
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}
} public interface UserDAO {

	public User findById(UUID id) throws DAOException;
	
	public User getByEmail(String email) throws DAOException;

	public List<User> findAll() throws DAOException;
	
	public List<User> findByItemId(Long clientFileId) throws DAOException;

	public void add(User user) throws DAOException;

	public void update(User user) throws DAOException;

	public void delete(UUID id) throws DAOException;
	
	public void updateAvailableQuota(User user) throws DAOException;
} public interface WorkspaceDAO {

	public Workspace getById(UUID id) throws DAOException;

	public List<Workspace> getByUserId(UUID userId) throws DAOException;
	
	public Workspace getDefaultWorkspaceByUserId(UUID userId) throws DAOException;
	
	public Workspace getByItemId(Long itemId) throws DAOException;

	public void add(Workspace workspace) throws DAOException;

	public void update(User user, Workspace workspace) throws DAOException;

	public void addUser(User user, Workspace workspace) throws DAOException;
	
	public void deleteUser(User user, Workspace workspace) throws DAOException;

	public void delete(UUID id) throws DAOException;
	
	public List<UserWorkspace> getMembersById(UUID workspaceId) throws DAOException;

} public interface APIHandler {
	
	public APIGetMetadata getMetadata(User user, Long fileId, Boolean includeChunks, Long version, Boolean isFolder);
	
	public APICommitResponse createFile(User user, ItemMetadata fileToSave);
	
	public APICommitResponse updateData(User user, ItemMetadata fileToUpdate);
	
	public APICommitResponse updateMetadata(User user, ItemMetadata fileToUpdate, Boolean parentUpdated);

	public APICreateFolderResponse createFolder(User user, ItemMetadata item);

	public APIRestoreMetadata restoreMetadata(User user, ItemMetadata item);

	public APIDeleteResponse deleteItem(User user, ItemMetadata item);

	public APIGetVersions getVersions(User user, ItemMetadata item);
	
	public APIShareFolderResponse shareFolder(User user, Item item, List<String> emails);
	
	public APIUnshareFolderResponse unshareFolder(User user, Item item, List<String> emails);
	
	public APIGetWorkspaceInfoResponse getWorkspaceInfo(User user, ItemMetadata item);
	
	public APIGetFolderMembersResponse getFolderMembers(User user, Item item);
} public class SQLAPIHandler extends Handler implements APIHandler {

    private static final Logger logger = Logger.getLogger(SQLAPIHandler.class.getName());
    private Device apiDevice = new Device(Constants.API_DEVICE_ID);

    public SQLAPIHandler(ConnectionPool pool) throws SQLException,
            NoStorageManagerAvailable {
        super(pool);
    }

    @Override
    public APIGetMetadata getMetadata(User user, Long fileId,
            Boolean includeChunks, Long version, Boolean isFolder) {

        ItemMetadata responseObject = null;
        Integer errorCode = 0;
        Boolean success = false;
        String description = "";

        try {

            if (fileId == null) {
                // retrieve metadata from the root folder
                responseObject = this.itemDao.findByUserId(user.getId(), false);
            } else {

                // check if user has permission on this file
                List<User> users = this.userDao.findByItemId(fileId);

                if (users.isEmpty()) {
                    throw new DAOException(DAOError.FILE_NOT_FOUND);
                }

                if (!userHasPermission(user, users)) {
                    throw new DAOException(DAOError.USER_NOT_AUTHORIZED);
                }

                responseObject = this.itemDao.findById(fileId, false, version,
                        false, includeChunks);
            }

            if (responseObject.isFolder() != isFolder) {
                throw new DAOException(DAOError.FILE_NOT_FOUND);
            }

            success = true;

        } catch (DAOException e) {
            description = e.getError().getMessage();
            errorCode = e.getError().getCode();
            logger.error(e.toString(), e);
        }

        APIGetMetadata response = new APIGetMetadata(responseObject, success,
                errorCode, description);
        return response;
    }

    public APIGetMetadata getFolderContent(User user, Long folderId,
            Boolean includeDeleted) {

        ItemMetadata responseObject = null;
        Integer errorCode = 0;
        Boolean success = false;
        String description = "";

        try {

            if (folderId == null) {
                // retrieve metadata from the root folder
                responseObject = this.itemDao.findByUserId(user.getId(),
                        includeDeleted);
            } else {

                // check if user has permission on this file
                List<User> users = this.userDao.findByItemId(folderId);

                if (users.isEmpty()) {
                    throw new DAOException(DAOError.FILE_NOT_FOUND);
                }

                if (!userHasPermission(user, users)) {
                    throw new DAOException(DAOError.USER_NOT_AUTHORIZED);
                }

                responseObject = this.itemDao.findById(folderId, true, null,
                        includeDeleted, false);
            }

            success = true;

        } catch (DAOException e) {
            description = e.getError().getMessage();
            errorCode = e.getError().getCode();
            logger.error(e.toString(), e);
        }

        APIGetMetadata response = new APIGetMetadata(responseObject, success,
                errorCode, description);
        return response;
    }

    @Override
    public APICommitResponse createFile(User user, ItemMetadata fileToSave) {

        // Check the owner
        try {
            user = userDao.findById(user.getId());
        } catch (DAOException e) {
            logger.error(e);
            return new APICommitResponse(fileToSave, false, 404,
                    "User not found.");
        }

        // Get user workspaces
        try {
            List<Workspace> workspaces = workspaceDAO.getByUserId(user.getId());
            user.setWorkspaces(workspaces);
        } catch (DAOException e) {
            logger.error(e);
            return new APICommitResponse(fileToSave, false, 404,
                    "No workspaces found for the user.");
        }

        boolean includeList = true;
        Long version = null;
        boolean includeDeleted = false;
        boolean includeChunks = false;

        // check that the given parent ID exists
        ItemMetadata parent;
        if (fileToSave.getParentId() != null) {
            try {
                parent = itemDao.findById(fileToSave.getParentId(),
                        includeList, version, includeDeleted, includeChunks);
                fileToSave.setParentVersion(parent.getVersion());

                // check if parent is a folder
                if (!parent.isFolder()) {
                    return new APICommitResponse(fileToSave, false, 400,
                            "Parent must be a folder, not a file.");
                }

            } catch (DAOException e) {
                return new APICommitResponse(fileToSave, false, 404,
                        "Parent folder not found");
            }
        } else {
            try {
                parent = this.itemDao
                        .findByUserId(user.getId(), includeDeleted);
                Workspace parentWorkspace = workspaceDAO
                        .getDefaultWorkspaceByUserId(user.getId());
                parent.setWorkspaceId(parentWorkspace.getId());
            } catch (DAOException e) {
                return new APICommitResponse(fileToSave, false, e.getError()
                        .getCode(), e.getMessage());
            }
        }

        // check if the user has permission on the file and parent
        boolean permissionParent = false;
        for (Workspace w : user.getWorkspaces()) {
            if (parent.isRoot() || w.getId().equals(parent.getWorkspaceId())) {
                permissionParent = true;
                break;
            }
        }
        if (!permissionParent) {
            return new APICommitResponse(fileToSave, false, 403,
                    "You are not allowed to modify this file");
        }

        // check if there is already a file with the same name
        boolean repeated = false;
        for (ItemMetadata child : parent.getChildren()) {
            if (child.getFilename().equals(fileToSave.getFilename())) {
                repeated = true;
                break;
            }
        }
        if (repeated) {
            return new APICommitResponse(fileToSave, false, 400,
                    "This name is already used in the same folder. Please use a different one. ");
        }

        APICommitResponse responseAPI;

        try {
            CommitNotification commitResult = saveNewItemAPI(user, fileToSave, parent);
            responseAPI = new APICommitResponse(fileToSave, true, 0, "");
            responseAPI.setQuotaLimit(commitResult.getLimitQuota());
            responseAPI.setQuotaUsed(commitResult.getUsedQuota());
        } catch (Exception e) {
            logger.error(e);
            responseAPI = new APICommitResponse(fileToSave, false, 500,
                    e.toString());
        }

        return responseAPI;
    }

    @Override
    public APICommitResponse updateData(User user, ItemMetadata fileToUpdate) {

        // Check the owner
        try {
            user = userDao.findById(user.getId());
        } catch (DAOException e) {
            logger.error(e);
            return new APICommitResponse(fileToUpdate, false, 404,
                    "User not found.");
        }

        // Get user workspaces
        try {
            List<Workspace> workspaces = workspaceDAO.getByUserId(user.getId());
            user.setWorkspaces(workspaces);
        } catch (DAOException e) {
            logger.error(e);
            return new APICommitResponse(fileToUpdate, false, 404,
                    "No workspaces found for the user.");
        }

        boolean includeList = true;
        Long version = null;
        boolean includeDeleted = false;
        boolean includeChunks = false;

        // check that the given file ID exists
        ItemMetadata file;
        try {
            file = itemDao.findById(fileToUpdate.getId(), includeList, version,
                    includeDeleted, includeChunks);
        } catch (DAOException e) {
            return new APICommitResponse(fileToUpdate, false, 404,
                    "File not found");
        }

        // check if the user has permission on the file and parent
        boolean permission = false;
        for (Workspace w : user.getWorkspaces()) {
            if (w.getId().equals(file.getWorkspaceId())) {
                permission = true;
            }
        }
        if (!permission) {
            return new APICommitResponse(fileToUpdate, false, 403,
                    "You are not allowed to modify this file");
        }

        // update file attributes

        file.setMimetype(fileToUpdate.getMimetype());
        file.setChecksum(fileToUpdate.getChecksum());
        file.setSize(fileToUpdate.getSize());
        file.setChunks(fileToUpdate.getChunks());
        file.setVersion(file.getVersion() + 1L);
        file.setModifiedAt(new Date());
        file.setStatus(Status.CHANGED.toString());

        // Commit the file
        List<ItemMetadata> items = new ArrayList<ItemMetadata>();
        items.add(file);

        Workspace workspace = new Workspace(file.getWorkspaceId());

        APICommitResponse responseAPI;
        try {
            CommitNotification commitResult = this.doCommit(user, workspace, apiDevice, items);
            responseAPI = new APICommitResponse(file, true, 0, "");
            responseAPI.setQuotaLimit(commitResult.getLimitQuota());
            responseAPI.setQuotaUsed(commitResult.getUsedQuota());
        } catch (Exception e) {
            logger.error(e);
            responseAPI = new APICommitResponse(file, false, 500, e.toString());
        }

        return responseAPI;
    }

    @Override
    public APICommitResponse updateMetadata(User user, ItemMetadata fileToUpdate, Boolean parentUpdated) {

        // Check the owner
        try {
            user = userDao.findById(user.getId());
        } catch (DAOException e) {
            logger.error(e);
            return new APICommitResponse(fileToUpdate, false, 404,
                    "User not found.");
        }

        // Get user workspaces
        try {
            List<Workspace> workspaces = workspaceDAO.getByUserId(user.getId());
            user.setWorkspaces(workspaces);
        } catch (DAOException e) {
            logger.error(e);
            return new APICommitResponse(fileToUpdate, false, 404,
                    "No workspaces found for the user.");
        }

        boolean includeList = true;
        Long version = null;
        boolean includeDeleted = false;
        boolean includeChunks = true;

        // check that the given file ID exists
        ItemMetadata file;
        try {
            file = itemDao.findById(fileToUpdate.getId(), includeList, version,
                    includeDeleted, includeChunks);
        } catch (DAOException e) {
            return new APICommitResponse(fileToUpdate, false, 404,
                    "File not found");
        }

        // check that the given parent ID exists
        ItemMetadata parent;
        if (fileToUpdate.getParentId() != null) {
            try {
                parent = itemDao.findById(fileToUpdate.getParentId(),
                        includeList, version, includeDeleted, includeChunks);

                // check if parent is a folder
                if (!parent.isFolder()) {
                    return new APICommitResponse(fileToUpdate, false, 400, "Parent must be a folder, not a file.");
                }

            } catch (DAOException e) {
                return new APICommitResponse(fileToUpdate, false, 404, "Parent folder not found");
            }
        } else {
            try {
                parent = this.itemDao.findByUserId(user.getId(), includeDeleted);
            } catch (DAOException e) {
                return new APICommitResponse(fileToUpdate, false, e.getError().getCode(), e.getMessage());
            }
        }

        // check if the user has permission on the file and parent
        boolean permissionFile = false;
        boolean permissionParent = false;
        for (Workspace w : user.getWorkspaces()) {
            if (w.getId().equals(file.getWorkspaceId())) {
                permissionFile = true;
            }
            if (parent.isRoot() || w.getId().equals(parent.getWorkspaceId())) {
                permissionParent = true;
            }
        }
        if (!permissionFile || !permissionParent) {
            return new APICommitResponse(fileToUpdate, false, 403,
                    "You are not allowed to modify this file");
        }

        // check if there is already a file with the same name
        boolean repeated = false;
        for (ItemMetadata child : parent.getChildren()) {
            if (child.getFilename().equals(fileToUpdate.getFilename())) {
                repeated = true;
            }
        }
        if (repeated) {
            return new APICommitResponse(fileToUpdate, false, 400,
                    "This name is already used in the same folder. Please use a different one. ");
        }

        // update file attributes
        if (fileToUpdate.getFilename() != null) {
            file.setFilename(fileToUpdate.getFilename());
        }
        if (parentUpdated) {
            file.setParentId(parent.getId());
            file.setParentVersion(parent.getVersion());
        }
        file.setVersion(file.getVersion() + 1L);
        file.setModifiedAt(new Date());
        file.setStatus(Status.RENAMED.toString());

        // Commit the file
        List<ItemMetadata> items = new ArrayList<ItemMetadata>();
        items.add(file);

        Workspace workspace = new Workspace(file.getWorkspaceId());
        
        APICommitResponse responseAPI;
        try {
            CommitNotification commitResult = this.doCommit(user, workspace, apiDevice, items);
            responseAPI = new APICommitResponse(file, true, 0, "");
            responseAPI.setQuotaLimit(commitResult.getLimitQuota());
            responseAPI.setQuotaUsed(commitResult.getUsedQuota());
        } catch (Exception e) {
            logger.error(e);
            responseAPI = new APICommitResponse(file, false, 500, e.toString());
        }

        return responseAPI;
    }

    @Override
    public APICreateFolderResponse createFolder(User user, ItemMetadata item) {

        // Check the owner
        try {
            user = userDao.findById(user.getId());
        } catch (DAOException e) {
            logger.error(e);
            APICreateFolderResponse response = new APICreateFolderResponse(
                    item, false, 404, "User not found.");
            return response;
        }

        // get metadata of the parent item
        APIGetMetadata parentResponse = this.getFolderContent(user,
                item.getParentId(), false);
        ItemMetadata parentMetadata = parentResponse.getItemMetadata();

        // if it is the root, get the default workspace
        if (parentMetadata.isRoot()) {

            try {
                Workspace workspace = workspaceDAO
                        .getDefaultWorkspaceByUserId(user.getId());
                parentMetadata.setWorkspaceId(workspace.getId());
            } catch (DAOException e) {
                logger.error(e);
                APICreateFolderResponse response = new APICreateFolderResponse(
                        item, false, 404, "Workspace not found.");
                return response;
            }
        } else {

            if (!parentMetadata.isFolder()) {
                return new APICreateFolderResponse(item, false, 400,
                        "Parent must be a folder, not a file.");
            }

            item.setParentVersion(parentMetadata.getVersion());
        }

        String folderName = item.getFilename();
        List<ItemMetadata> files = parentMetadata.getChildren();

        // check if there exists a folder with the same name
        ItemMetadata object = null;
        for (ItemMetadata file : files) {
            if (file.getFilename().equals(folderName)
                    && !file.getStatus().equals("DELETED")) {
                object = file;
                break;
            }
        }

        if (object != null) {
            APICreateFolderResponse response = new APICreateFolderResponse(
                    object, false, 400, "Folder already exists.");
            return response;
        }

        APICreateFolderResponse responseAPI = this.createNewFolder(user, item, parentMetadata);
        
        return responseAPI;
    }

    @Override
    public APIRestoreMetadata restoreMetadata(User user, ItemMetadata item) {
        try {

            Item serverItem = itemDao.findById(item.getId());
            ItemMetadata lastObjectVersion = itemDao.findById(item.getId(),
                    false, null, false, false);
            if (serverItem != null && lastObjectVersion != null) {

                ItemMetadata metadata = itemVersionDao.findByItemIdAndVersion(
                        serverItem.getId(), item.getVersion());

                ItemVersion restoredObject = new ItemVersion(metadata);

                if (restoredObject.getStatus().compareTo(
                        Status.DELETED.toString()) != 0) {
                    restoredObject
                            .setVersion(lastObjectVersion.getVersion() + 1);
                    restoredObject.setStatus(Status.CHANGED.toString());

                    // save restoredObject
                    itemVersionDao.add(restoredObject);

                    List<String> chunks = new ArrayList<String>();
                    // If no folder, create new chunks
                    if (!restoredObject.getChunks().isEmpty()) {
                        for (Chunk chunk : restoredObject.getChunks()) {
                            chunks.add(chunk.getClientChunkName());
                        }
                        this.createChunks(chunks, restoredObject);
                    }

                    serverItem.setLatestVersion(restoredObject.getVersion());
                    itemDao.put(serverItem);

                    item.setChecksum(restoredObject.getChecksum());
                    item.setChunks(chunks);
                    item.setModifiedAt(restoredObject.getModifiedAt());
                    item.setDeviceId(restoredObject.getDevice().getId());
                    item.setFilename(restoredObject.getItem().getFilename());
                    item.setSize(restoredObject.getSize());

                    item.setIsFolder(serverItem.isFolder());
                    item.setMimetype(serverItem.getMimetype());

                    item.setParentVersion(serverItem
                            .getClientParentFileVersion());

                    item.setStatus(restoredObject.getStatus());
                    item.setVersion(restoredObject.getVersion());

                    APIRestoreMetadata response = new APIRestoreMetadata(item,
                            true, 200, "");
                    return response;
                } else {
                    APIRestoreMetadata response = new APIRestoreMetadata(item,
                            false, 400, "File not found.");
                    return response;
                }
            } else {
                APIRestoreMetadata response = new APIRestoreMetadata(item,
                        false, 400, "File not found.");
                return response;
            }
        } catch (DAOException e) {
            APIRestoreMetadata response = new APIRestoreMetadata(item, false,
                    400, e.getMessage());
            return response;
        }
    }

    @Override
    public APIDeleteResponse deleteItem(User user, ItemMetadata item) {
        List<ItemMetadata> filesToDelete;

        // Check the owner
        try {
            user = userDao.findById(user.getId());
        } catch (DAOException e) {
            logger.error(e);
            return new APIDeleteResponse(null, false, 404, "User not found.");
        }

        // Get user workspaces
        try {
            List<Workspace> workspaces = workspaceDAO.getByUserId(user.getId());
            user.setWorkspaces(workspaces);
        } catch (DAOException e) {
            logger.error(e);
            return new APIDeleteResponse(null, false, 404,
                    "No workspaces found for the user.");
        }

        // check that the given file ID exists
        try {
            filesToDelete = itemDao.getItemsById(item.getId());
        } catch (DAOException e) {
            return new APIDeleteResponse(null, false, 404,
                    "File or folder not found");
        }
        if (filesToDelete.isEmpty()) {
            return new APIDeleteResponse(null, false, 404,
                    "File or folder not found.");
        }

        // check if it's a file or a folder
        if (filesToDelete.get(0).isFolder() != item.isFolder()) {
            return new APIDeleteResponse(null, false, 400,
                    "Type missmatch (file and folder)");
        }

        // check if the user has permission on the file and parent
        boolean permission = false;
        for (Workspace w : user.getWorkspaces()) {
            if (w.getId().equals(filesToDelete.get(0).getWorkspaceId())) {
                permission = true;
            }
        }
        if (!permission) {
            return new APIDeleteResponse(null, false, 403,
                    "You are not allowed to deleted this file");
        }

        Workspace workspace = new Workspace(filesToDelete.get(0)
                .getWorkspaceId());

        APIDeleteResponse response;
        try {
            response = deleteItemsAPI(user, workspace, filesToDelete);
        } catch (DAOException e) {
            logger.error(e.toString(), e);
            response = new APIDeleteResponse(null, false, e.getError()
                    .getCode(), e.getMessage());
        }

        return response;
    }

    @Override
    public APIGetVersions getVersions(User user, ItemMetadata item) {
        ItemMetadata serverItem;

        // Check the owner
        try {
            user = userDao.findById(user.getId());
        } catch (DAOException e) {
            logger.error(e);
            return new APIGetVersions(null, false, 404, "User not found.");
        }

        // Get user workspaces
        try {
            List<Workspace> workspaces = workspaceDAO.getByUserId(user.getId());
            user.setWorkspaces(workspaces);
        } catch (DAOException e) {
            logger.error(e);
            return new APIGetVersions(null, false, 404,
                    "No workspaces found for the user.");
        }

        // check that the given file ID exists
        try {
            serverItem = itemDao.findItemVersionsById(item.getId());
        } catch (DAOException e) {
            return new APIGetVersions(null, false, 404,
                    "File or folder not found");
        }

        // check if it's a file or a folder
        if (serverItem.isFolder()) {
            return new APIGetVersions(null, false, 400,
                    "Incorrect file type. Must be a file, not a folder.");
        }

        APIGetVersions response = new APIGetVersions(serverItem, true, 0, "");
        return response;
    }

    @Override
    public APIShareFolderResponse shareFolder(User user, Item item,
            List<String> emails) {

        APIShareFolderResponse response;

        Workspace workspace;
        try {
            workspace = this.doShareFolder(user, emails, item, false);
            response = new APIShareFolderResponse(workspace, true, 0, "");
        } catch (ShareProposalNotCreatedException e) {
            response = new APIShareFolderResponse(null, false, 400,
                    e.getMessage());
        } catch (UserNotFoundException e) {
            response = new APIShareFolderResponse(null, false, 404,
                    e.getMessage());
        }

        return response;
    }

    @Override
    public APIUnshareFolderResponse unshareFolder(User user, Item item,
            List<String> emails) {

        APIUnshareFolderResponse response;
        UnshareData infoUnshare;

        try {
            infoUnshare = this.doUnshareFolder(user, emails, item, false);
            response = new APIUnshareFolderResponse(infoUnshare.getWorkspace(),
                    infoUnshare.getUsersToRemove(), infoUnshare.isUnshared(),
                    true, 0, "");
        } catch (ShareProposalNotCreatedException e) {
            response = new APIUnshareFolderResponse(null, null, false, false, 400,
                    e.getMessage());
        } catch (UserNotFoundException e) {
            response = new APIUnshareFolderResponse(null, null, false, false, 404,
                    e.getMessage());
        }

        return response;
    }

    @Override
    public APIGetFolderMembersResponse getFolderMembers(User user, Item item) {

        APIGetFolderMembersResponse response;

        // Check the owner
        try {
            user = userDao.findById(user.getId());
        } catch (NoResultReturnedDAOException e) {
            logger.warn(e);
            return new APIGetFolderMembersResponse(null, false, 404,
                    e.toString());
        } catch (DAOException e) {
            logger.error(e);
            return new APIGetFolderMembersResponse(null, false, 500,
                    e.toString());
        }

        // Get folder metadata
        try {
            item = itemDao.findById(item.getId());
        } catch (DAOException e) {
            logger.error(e);
            return new APIGetFolderMembersResponse(null, false, 500,
                    e.toString());
        }

        if (item == null || !item.isFolder()) {
            return new APIGetFolderMembersResponse(null, false, 404,
                    "No folder found with the given ID.");
        }

        List<UserWorkspace> members;
        try {
            members = this.doGetWorkspaceMembers(user, item.getWorkspace());
        } catch (InternalServerError e) {
            return new APIGetFolderMembersResponse(null, false, 500,
                    e.toString());
        }

        response = new APIGetFolderMembersResponse(members, true, 0, "");

        return response;
    }

    @Override
    public APIGetWorkspaceInfoResponse getWorkspaceInfo(User user,
            ItemMetadata item) {

        // Check the owner
        try {
            user = userDao.findById(user.getId());
        } catch (DAOException e) {
            logger.error(e);
            return new APIGetWorkspaceInfoResponse(null, false, 404,
                    "User not found.");
        }

        // Get user workspaces
        try {
            List<Workspace> workspaces = workspaceDAO.getByUserId(user.getId());
            user.setWorkspaces(workspaces);
        } catch (DAOException e) {
            logger.error(e);
            return new APIGetWorkspaceInfoResponse(null, false, 404,
                    "No workspaces found for the user.");
        }

        // get the workspace

        Workspace workspace;
        if (item.getId() == null) {
            try {
                workspace = workspaceDAO.getDefaultWorkspaceByUserId(user
                        .getId());
            } catch (DAOException e) {
                return new APIGetWorkspaceInfoResponse(null, false, 404,
                        "Workspace not found");
            }
        } else {
            try {
                workspace = workspaceDAO.getByItemId(item.getId());
            } catch (DAOException e) {
                return new APIGetWorkspaceInfoResponse(null,false, 404,
                        "Workspace not found");
            }
        }

        // check if the user has permission on the file and parent
        boolean permission = false;
        for (Workspace w : user.getWorkspaces()) {
            if (item.getId() == null || w.getId().equals(workspace.getId())) {
                permission = true;
                break;
            }
        }
        if (!permission) {
            return new APIGetWorkspaceInfoResponse(null, false, 403,
                    "You are not allowed to access this file");
        }
        
        User workspaceOwner;
        try {
        	workspaceOwner = userDao.findById(workspace.getOwner().getId());
        } catch (DAOException e) {
            logger.error(e);
            return new APIGetWorkspaceInfoResponse(null, false, 404,
                    "User not found.");
        }
        workspace.setOwner(workspaceOwner);
        APIGetWorkspaceInfoResponse response = new APIGetWorkspaceInfoResponse(
                workspace,  true, 0, "");
        return response;
    }

    private boolean userHasPermission(User user, List<User> users) {
        boolean hasPermission = false;
        for (User u : users) {
            if (u.getId().equals(user.getId())) {
                hasPermission = true;
                break;
            }
        }
        return hasPermission;
    }

    private CommitNotification saveNewItemAPI(User user, ItemMetadata itemToSave,
            ItemMetadata parent) throws DAOException {

        itemToSave.setWorkspaceId(parent.getWorkspaceId());
        Workspace workspace = new Workspace(parent.getWorkspaceId());

        List<ItemMetadata> objects = new ArrayList<ItemMetadata>();
        objects.add(itemToSave);

        return this.doCommit(user, workspace, apiDevice, objects);

    }

    private APICreateFolderResponse createNewFolder(User user, ItemMetadata item, ItemMetadata parent) {

        // Create metadata

        if (!parent.isRoot()) {
            item.setParentId(parent.getId());
            item.setParentVersion(parent.getVersion());
        }

        item.setVersion(1L);
        item.setWorkspaceId(parent.getWorkspaceId());
        item.setStatus("NEW");
        item.setSize(0L);
        item.setIsFolder(true);
        item.setMimetype("inode/directory");
        item.setModifiedAt(new Date());
        item.setDeviceId(Constants.API_DEVICE_ID);
        item.setChecksum(0L);

        List<ItemMetadata> items = new ArrayList<ItemMetadata>();
        items.add(item);

        Workspace workspace = new Workspace(item.getWorkspaceId());

        CommitNotification commitResult;
        try {
            commitResult = this.doCommit(user, workspace, apiDevice, items);
        } catch (DAOException e) {
            logger.error(e);
            return new APICreateFolderResponse(item, false, 500, "Item could not be committed.");
        }
        
        APICreateFolderResponse responseAPI;
        if (!commitResult.getItems().get(0).isCommitSucceed()) {
            responseAPI = new APICreateFolderResponse(item, false, 500, "Item could not be committed.");
            return responseAPI;
        }

        APICreateFolderResponse response = new APICreateFolderResponse(item, true, 0, "");
        response.setQuotaLimit(commitResult.getLimitQuota());
        response.setQuotaUsed(commitResult.getUsedQuota());
        return response;
    }

    private void createChunks(List<String> chunksString,
            ItemVersion objectVersion) throws IllegalArgumentException,
            DAOException {

        if (chunksString.size() > 0) {
            List<Chunk> chunks = new ArrayList<Chunk>();
            int i = 0;

            for (String chunkName : chunksString) {
                chunks.add(new Chunk(chunkName, i));
                i++;
            }

            itemVersionDao.insertChunks(chunks, objectVersion.getId());
        }
    }

    private APIDeleteResponse deleteItemsAPI(User user, Workspace workspace,
            List<ItemMetadata> filesToDelete) throws DAOException {

        List<ItemMetadata> items = new ArrayList<ItemMetadata>();

        for (ItemMetadata fileToDelete : filesToDelete) {

            if (fileToDelete.getStatus().equals("DELETED")) {
                continue;
            }

            fileToDelete.setStatus("DELETED");
            // fileToDelete.setFileSize(0L);
            fileToDelete.setChunks(new ArrayList<String>());
            // fileToDelete.setChecksum(0L);
            fileToDelete.setVersion(fileToDelete.getVersion() + 1);

            Date date = new Date();
            fileToDelete.setModifiedAt(date);

            items.add(fileToDelete);
        }

        Boolean success = false;
        ItemMetadata fileToDelete = null;

        CommitNotification commitResult = this.doCommit(user, workspace,
                apiDevice, items);

        if (!commitResult.getItems().isEmpty()) {
            fileToDelete = commitResult.getItems().get(0).getMetadata();
            success = true;
        }

        APIDeleteResponse response = new APIDeleteResponse(fileToDelete, success, 0, "");
        response.setQuotaLimit(commitResult.getLimitQuota());
        response.setQuotaUsed(commitResult.getUsedQuota());
        
        return response;
    }
} public class APICommitResponse extends APIResponse {

    public APICommitResponse(ItemMetadata item, Boolean success, int error, String description) {
        this.success = success;
        this.errorCode = error;
        this.description = description;
        if (item != null) {
            this.item = new CommitInfo(item.getVersion(),
                    success, item);
        }
    }
} public class APIGetWorkspaceInfoResponse extends APIResponse {

	private Workspace workspace;

	public APIGetWorkspaceInfoResponse(Workspace workspace, Boolean success, int error, String description) {
		super();
		this.success = success;
		this.description = description;
		this.errorCode = error;
		this.workspace = workspace;
	}

	public Workspace getWorkspace() {
		return workspace;
	}

	@Override
	public String toString() {
		JsonObject jResponse;

		if (!getSuccess()) {
			jResponse = new JsonObject();
			jResponse.addProperty("description", getDescription());
			jResponse.addProperty("error", getErrorCode());
		} else {
			jResponse = this.parseWorkspace();
		}

		return jResponse.toString();
	}

	protected JsonObject parseWorkspace() {

		JsonObject jMetadata = new JsonObject();

		if (workspace == null) {
			return jMetadata;
		}

		jMetadata.addProperty("id", workspace.getId().toString());
		jMetadata.addProperty("name", workspace.getName());
		jMetadata.addProperty("swift_container", workspace.getSwiftContainer());
		jMetadata.addProperty("is_shared", workspace.isShared());
		jMetadata.addProperty("owner", workspace.getOwner().getId().toString());
		jMetadata.addProperty("latest_revision", workspace.getLatestRevision());
		jMetadata.addProperty("parent_item_id", workspace.getParentItem().getId());
		jMetadata.addProperty("is_encrypted", workspace.isEncrypted());
		jMetadata.addProperty("quota_used", workspace.getOwner().getQuotaUsedLogical().toString());
		jMetadata.addProperty("quota_limit", workspace.getOwner().getQuotaLimit().toString());


		return jMetadata;
	}

} public class Config {

	private static Properties properties;
	private static final Logger logger = Logger.getLogger(Config.class.getName());
	private static final String[] PASSWORD_KEYS = new String[]{Constants.PROP_OMQ_PASSWORD, 
		Constants.PROP_POSTGRESQL_PASSWORD, Constants.PROP_SWIFT_PASSWORD}; 

	public static void loadProperties() throws IOException {
		logger.warn(String.format("Config argument not passed, will use default config file: '%s'",
				Constants.DEFAULT_CONFIG_FILE));

		loadProperties(Constants.DEFAULT_CONFIG_FILE);
	}

	public static void loadProperties(String configFileUrl) throws IOException {

		logger.info(String.format("Loading config file: '%s'", configFileUrl));

		URL log4jResource = Config.class.getResource("/log4j.xml");
		DOMConfigurator.configure(log4jResource);

		properties = new Properties();

		properties.load(new FileInputStream(configFileUrl));

		validateProperties();

		logger.info("Configuration file loaded");

		displayConfiguration();
	}

	public static Properties getProperties() {
		return properties;
	}

	private static void validateProperties() {
		checkProperty(Constants.PROP_DATASOURCE, Constants.DEFAULT_DATASOURCE);

		// ObjectMQ
		checkProperty(Constants.PROP_OMQ_HOST, Constants.DEFAULT_OMQ_HOST);
		checkProperty(Constants.PROP_OMQ_PORT, Constants.DEFAULT_OMQ_PORT);
		checkProperty(Constants.PROP_OMQ_THREADS, Constants.DEFAULT_OMQ_THREADS);
		checkProperty(Constants.PROP_OMQ_EXCHANGE, Constants.DEFAULT_OMQ_EXCHANGE);
		checkProperty(Constants.PROP_OMQ_USER, Constants.DEFAULT_OMQ_USER);
		checkProperty(Constants.PROP_OMQ_PASSWORD, Constants.DEFAULT_OMQ_PASSWORD);

		// Database
		checkProperty(Constants.PROP_POSTGRESQL_HOST, Constants.DEFAULT_POSTGRESQL_HOST);
		checkProperty(Constants.PROP_POSTGRESQL_PORT, Constants.DEFAULT_POSTGRESQL_PORT);
		checkProperty(Constants.PROP_POSTGRESQL_DATABASE, Constants.DEFAULT_POSTGRESQL_DATABASE);
		checkProperty(Constants.PROP_POSTGRESQL_USERNAME, Constants.DEFAULT_POSTGRESQL_USERNAME);
		checkProperty(Constants.PROP_POSTGRESQL_PASSWORD, Constants.DEFAULT_POSTGRESQL_PASSWORD);
	}

	private static void checkProperty(String key, Object defaultValue) {
		if (!properties.containsKey(key)) {
			logger.warn(String.format("Property '%s' not found, using default value: '%s'", key,
					defaultValue.toString()));
			properties.setProperty(key, defaultValue.toString());
		}
	}

	private static void displayConfiguration() {
		logger.info("Displaying configuration:");

		Enumeration<?> e = properties.propertyNames();
		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			if (!Arrays.asList(PASSWORD_KEYS).contains(key)){
				logger.info(String.format("%s : %s", key, properties.getProperty(key)));
			}
		}
	}

	public static String getDatasource() {
		return properties.getProperty(Constants.PROP_DATASOURCE);
	}

	public static String getOmqHost() {
		return properties.getProperty(Constants.PROP_OMQ_HOST);
	}

	public static Integer getOmqPort() {
		return Integer.parseInt(properties.getProperty(Constants.PROP_OMQ_PORT));
	}

	public static String getOmqExchange() {
		return properties.getProperty(Constants.PROP_OMQ_EXCHANGE);
	}

	public static String getOmqUser() {
		return properties.getProperty(Constants.PROP_OMQ_USER);
	}

	public static String getOmqPassword() {
		return properties.getProperty(Constants.PROP_OMQ_PASSWORD);
	}

	public static Integer getOmqNumThreads() {
		return Integer.parseInt(properties.getProperty(Constants.PROP_OMQ_THREADS, Constants.DEFAULT_OMQ_THREADS));
	}

	/* POSTGRESQL */

	public static String getPostgresqlHost() {
		return properties.getProperty(Constants.PROP_POSTGRESQL_HOST);
	}

	public static Integer getPostgresqlPort() {
		return Integer.parseInt(properties.getProperty(Constants.PROP_POSTGRESQL_PORT));
	}

	public static String getPostgresqlDatabase() {
		return properties.getProperty(Constants.PROP_POSTGRESQL_DATABASE);
	}

	public static String getPostgresqlUsername() {
		return properties.getProperty(Constants.PROP_POSTGRESQL_USERNAME);
	}

	public static String getPostgresqlPassword() {
		return properties.getProperty(Constants.PROP_POSTGRESQL_PASSWORD);
	}

	public static Integer getPostgresqlInitialConns() {
		return Integer.parseInt(properties.getProperty(Constants.PROP_POSTGRESQL_INITIAL_CONNS,
				Constants.DEFAULT_POSTGRESQL_INITIAL_CONNS));
	}

	public static Integer getPostgresqlMaxConns() {
		return Integer.parseInt(properties.getProperty(Constants.PROP_POSTGRESQL_MAX_CONNS,
				Constants.DEFAULT_POSTGRESQL_MAX_CONNS));
	}

	/* SWIFT */

	public static String getSwiftHost() {
		return properties.getProperty(Constants.PROP_SWIFT_HOST, Constants.DEFAULT_SWIFT_HOST);
	}
	
	public static Integer getSwiftPort() {
		return Integer.parseInt(properties.getProperty(Constants.PROP_SWIFT_PORT,
				Constants.DEFAULT_SWIFT_PORT));
	}

	public static String getSwiftProtocol() {
		return properties
				.getProperty(Constants.PROP_SWIFT_PROTOCOL, Constants.DEFAULT_SWIFT_PROTOCOL);
	}
	
	
	public static String getSwiftKeystoneHost() {
		return properties.getProperty(Constants.PROP_SWIFT_KEYSTONE_HOST, Constants.DEFAULT_SWIFT_KEYSTONE_HOST);
	}

	public static Integer getSwiftKeystoneAdminPort() {
		return Integer.parseInt(properties.getProperty(Constants.PROP_SWIFT_KEYSTONE_ADMIN_PORT,
				Constants.DEFAULT_SWIFT_KEYSTONE_ADMIN_PORT));
	}
	
	public static Integer getSwiftKeystonePort() {
		return Integer.parseInt(properties.getProperty(Constants.PROP_SWIFT_KEYSTONE_PORT,
				Constants.DEFAULT_SWIFT_KEYSTONE_PORT));
	}

	public static String getSwiftKeystoneProtocol() {
		return properties
				.getProperty(Constants.PROP_SWIFT_KEYSTONE_PROTOCOL, Constants.DEFAULT_SWIFT_KEYSTONE_PROTOCOL);
	}

	public static String getSwiftTenant() {
		return properties.getProperty(Constants.PROP_SWIFT_TENANT, Constants.DEFAULT_SWIFT_TENANT);
	}

	public static String getSwiftUser() {
		return properties.getProperty(Constants.PROP_SWIFT_USER, Constants.DEFAULT_SWIFT_USER);
	}

	public static String getSwiftPassword() {
		return properties.getProperty(Constants.PROP_SWIFT_PASSWORD, Constants.DEFAULT_SWIFT_PASSWORD);
	}
	
	public static String getSwiftAuthUrl(){
		String authUrl = String.format("%s://%s:%s/v2.0/tokens", getSwiftKeystoneProtocol(), getSwiftKeystoneHost(), getSwiftKeystonePort());
		return authUrl;
	}
	
	public static String getSwiftUrl(){
		String url = String.format("%s://%s:%s/v1", getSwiftProtocol(), getSwiftHost(), getSwiftPort());
		return url;
	}
}
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.UUID;
import org.junit.BeforeClass;
import org.junit.Test;
import com.stacksync.commons.models.ItemMetadata;
import com.stacksync.commons.models.User;
import com.stacksync.commons.models.Workspace;
import com.stacksync.syncservice.db.ConnectionPool;
import com.stacksync.syncservice.db.ConnectionPoolFactory;
import com.stacksync.syncservice.db.DAOFactory;
import com.stacksync.syncservice.db.UserDAO;
import com.stacksync.syncservice.db.WorkspaceDAO;
import com.stacksync.syncservice.handler.APIHandler;
import com.stacksync.syncservice.handler.SQLAPIHandler;
import com.stacksync.syncservice.rpc.messages.APICommitResponse;
import com.stacksync.syncservice.rpc.messages.APIGetWorkspaceInfoResponse;
import com.stacksync.syncservice.util.Config;
package com.stacksync.syncservice.test.handler;




public class GetWorkspaceInfoTest {

	private static APIHandler handler;
	private static WorkspaceDAO workspaceDAO;
	private static UserDAO userDao;
	private static User user1;
	private static User user2;

	@BeforeClass
	public static void initializeData() throws Exception {

		Config.loadProperties();

		String datasource = Config.getDatasource();
		ConnectionPool pool = ConnectionPoolFactory.getConnectionPool(datasource);