#region
/* -----------------------------------------------------------------------
*
*
* Copyright 2011-2012 GRNET S.A. All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and
* documentation are those of the authors and should not be
* interpreted as representing official policies, either expressed
* or implied, of GRNET S.A.
*
* -----------------------------------------------------------------------
*/
#endregion
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
namespace Pithos.Interfaces
{
[DebuggerDisplay("Name {Name}")]
public class ObjectInfo//:DynamicObject
{
private readonly List _knownContainers= new List{"trash"};
public string Name { get; set; }
public string Hash { get; set; }
public string X_Object_Hash { get { return Hash; } set { Hash = value; } }
[JsonProperty("x_object_uuid")]
public string UUID { get; set; }
public long Bytes { get; set; }
public string Content_Type { get; set; }
public DateTime Last_Modified { get; set; }
private Dictionary _tags=new Dictionary();
public Dictionary Tags
{
get { return _tags; }
set { _tags = value; }
}
private Dictionary _extensions=new Dictionary();
public Dictionary Extensions
{
get { return _extensions; }
set
{
_extensions = value;
ExtractKnownExtensions();
}
}
private Dictionary _permissions=new Dictionary();
[JsonProperty("x_object_sharing")]
[JsonConverter(typeof(PermissionConverter))]
public Dictionary Permissions
{
get { return _permissions; }
set
{
_permissions = value;
}
}
///
/// Version number
///
[JsonProperty("x_object_version")]
public long? Version { get; set; }
///
/// Shared object permissions can be Read or Write
///
[JsonProperty("x_object_allowed_to")]
public string AllowedTo { get; set; }
///
/// Version timestamp
///
[JsonProperty("X_Object_Version_Timestamp"), JsonConverter(typeof(PithosDateTimeConverter))]
public DateTime? VersionTimestamp { get; set; }
[JsonProperty("X_Object_Modified_By")]
public string ModifiedBy { get; set; }
public Stream Stream { get; set; }
public Uri StorageUri { get; set; }
public string Account { get; set; }
public string Container { get; set; }
public Uri Uri
{
get
{
var relativeUrl=String.Format("{0}/{1}/{2}",Account, Container,Name);
return StorageUri==null
? new Uri(relativeUrl,UriKind.Relative)
: new Uri(StorageUri, relativeUrl);
}
}
public string ContendDisposition { get; set; }
public string ContentEncoding { get; set; }
public string Manifest { get; set; }
public bool IsPublic
{
get { return !String.IsNullOrWhiteSpace(PublicUrl); }
set
{
if (!value)
PublicUrl = null;
else if (String.IsNullOrWhiteSpace(PublicUrl))
PublicUrl="true";
}
}
[JsonProperty("X_Object_Public")]
public string PublicUrl { get; set; }
public string PreviousHash { get; set; }
public ObjectInfo()
{}
public ObjectInfo(string accountPath,string accountName,FileSystemInfo fileInfo)
{
if (String.IsNullOrWhiteSpace(accountPath))
throw new ArgumentNullException("accountPath");
if (string.IsNullOrWhiteSpace(accountName))
throw new ArgumentNullException("accountName");
if (fileInfo == null)
throw new ArgumentNullException("fileInfo");
Contract.EndContractBlock();
var relativeUrl = fileInfo.WithProperCapitalization().AsRelativeUrlTo(accountPath);
//The first part of the URL is the container
var slashIndex = relativeUrl.IndexOf('/');
var container = relativeUrl.Substring(0, slashIndex);
//The second is the file's url relative to the container
var fileUrl = relativeUrl.Substring(slashIndex + 1);
Account = accountName;
Container = container;
Name = fileUrl;
}
private void ExtractKnownExtensions()
{
Version=GetLong(KnownExtensions.X_Object_Version);
VersionTimestamp = GetTimestamp(KnownExtensions.X_Object_Version_Timestamp);
ModifiedBy = GetString(KnownExtensions.X_Object_Modified_By);
}
private string GetString(string name)
{
string value;
_extensions.TryGetValue(name, out value);
return value ;
}
private long? GetLong(string name)
{
string version;
long value;
return _extensions.TryGetValue(name, out version) && long.TryParse(version, out value)
? (long?) value
: null;
}
private DateTime? GetTimestamp(string name)
{
string version;
DateTime value;
if (_extensions.TryGetValue(name, out version) &&
DateTime.TryParse(version,CultureInfo.InvariantCulture,DateTimeStyles.AdjustToUniversal, out value))
{
return value;
}
return null;
}
public static ObjectInfo Empty = new ObjectInfo
{
Name = String.Empty,
Hash = String.Empty,
Bytes = 0,
Content_Type = String.Empty,
Last_Modified = DateTime.MinValue,
Exists=false
};
private bool _exists=true;
public bool Exists
{
get {
return _exists;
}
set {
_exists = value;
}
}
public string RelativeUrlToFilePath(string currentAccount)
{
if (Name==null)
throw new InvalidOperationException("Name can't be null");
if (String.IsNullOrWhiteSpace(currentAccount))
throw new ArgumentNullException("currentAccount");
Contract.EndContractBlock();
if (this == Empty)
return String.Empty;
var unescaped = Uri.UnescapeDataString(Name);
var path = unescaped.Replace("/", "\\");
var pathParts=new Stack();
pathParts.Push(path);
if (!String.IsNullOrWhiteSpace(Container) && !_knownContainers.Contains(Container))
pathParts.Push(Container);
if (!currentAccount.Equals(Account, StringComparison.InvariantCultureIgnoreCase))
{
if (Account != null)
{
pathParts.Push(Account);
pathParts.Push(FolderConstants.OthersFolder);
}
}
var finalPath=Path.Combine(pathParts.ToArray());
return finalPath;
}
/*
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (binder.Name.StartsWith("x_object_meta"))
{
Tags[binder.Name] = value.ToString();
}
return false;
}
*/
public string GetPermissionString()
{
if (Permissions==null)
throw new InvalidOperationException();
Contract.EndContractBlock();
if (Permissions.Count == 0)
return "~";
var permissionBuilder = new StringBuilder();
var groupings = Permissions.GroupBy(pair => pair.Value.Trim(), pair => pair.Key.Trim());
foreach (var grouping in groupings)
{
permissionBuilder.AppendFormat("{0}={1};", grouping.Key, String.Join(",", grouping));
}
var permissions = Uri.EscapeDataString(permissionBuilder.ToString().Trim(';'));
return permissions;
}
public void SetPermissions(string permissions)
{
if (String.IsNullOrWhiteSpace(permissions))
return;
Permissions = PermissionConverter.ParsePermissions(permissions);
}
//The previous values that correspond to a NoModification object
//have the same account, container and possibly the same folder
public bool CorrespondsTo(ObjectInfo other)
{
return other.Account == this.Account
&& other.Container == this.Container
&& (this.Name == null || other.Name.StartsWith(this.Name));
}
public bool IsWritable(string account)
{
//If the Allowed To header has no value, try to determine the Share permissions
if (AllowedTo == null)
{
//If this file has no permissions defined, we can probably write it
//This case should occur only when the info comes from a listing of the user's own files
if (Permissions == null || Permissions.Count == 0)
return true;
string perms;
//Do we have an explicit write share to this account?
return Permissions.TryGetValue(account, out perms)
&& perms.Equals("write",StringComparison.InvariantCultureIgnoreCase);
}
//Otherwise return the permissions specified by AllowedTo
return AllowedTo.Equals("write",StringComparison.InvariantCultureIgnoreCase) ;
}
public ObjectInfo Previous { get; private set; }
public bool IsDirectory
{
get
{
if (Content_Type == null)
return false;
if (Content_Type.StartsWith(@"application/directory",StringComparison.InvariantCultureIgnoreCase))
return true;
if (Content_Type.StartsWith(@"application/folder",StringComparison.InvariantCultureIgnoreCase))
return true;
return false;
}
}
public Uri AccountKey
{
get { return new Uri(StorageUri,"../" + Account); }
}
public ObjectInfo SetPrevious(ObjectInfo previous)
{
Previous = previous;
PreviousHash = previous.Hash;
return this;
}
}
}