feedquery.cs :  » Network-Clients » RemoteCalendars » Google » GData » Client » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Network Clients » RemoteCalendars 
RemoteCalendars » Google » GData » Client » feedquery.cs
/* Copyright (c) 2006 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/
#region Using directives

#define USE_TRACING

using System;
using System.Xml;
using System.Text; 
using System.Globalization;
using System.Diagnostics;

#endregion

namespace Google.GData.Client{


    //////////////////////////////////////////////////////////////////////
    /// <summary>Enum to describe the different category boolean operations.
    /// </summary> 
    //////////////////////////////////////////////////////////////////////
    public enum QueryCategoryOperator
    {
        /// <summary>A logical AND operation.</summary>
        AND,                       
        /// <summary>A logical OR operation.</summary>
        OR
    }
    /////////////////////////////////////////////////////////////////////////////




    //////////////////////////////////////////////////////////////////////
    /// <summary>Base class to hold an Atom category plus the boolean
    /// to create the query category.
    /// </summary> 
    //////////////////////////////////////////////////////////////////////
    public class QueryCategory 
    {
        /// <summary>AtomCategory holder.</summary> 
        private AtomCategory category;
        /// <summary>Boolean operator (can be OR or AND).</summary> 
        private QueryCategoryOperator categoryOperator; 
        /// <summary>Boolean negator (can be true or false).</summary> 
        private bool isExcluded; 

        
        //////////////////////////////////////////////////////////////////////
        /// <summary>Constructor, given a category.</summary>
        //////////////////////////////////////////////////////////////////////
        public QueryCategory(AtomCategory category)
        {
            this.category = category;
            this.categoryOperator = QueryCategoryOperator.AND; 
        }



        //////////////////////////////////////////////////////////////////////
        /// <summary>Constructor, given a category as a string from the URI.</summary>
        //////////////////////////////////////////////////////////////////////
        public QueryCategory(string strCategory, QueryCategoryOperator op)
        {
            Tracing.TraceMsg("Depersisting category from: " + strCategory); 
            this.categoryOperator = op; 
            strCategory = FeedQuery.CleanPart(strCategory); 

            // let's parse the string
            if (strCategory[0] == '-')
            {
                // negator
                this.isExcluded = true; 
                // remove him
                strCategory = strCategory.Substring(1, strCategory.Length-1); 
            }

            // let's extract the scheme if there is one...
            int iStart = strCategory.IndexOf('{') ; 
            int iEnd = strCategory.IndexOf('}') ; 
            AtomUri scheme = null; 
            if (iStart != -1 && iEnd != -1)
            {
                // 
                iEnd++;
                iStart++;
                scheme = new AtomUri(strCategory.Substring(iStart, iEnd- iStart-1)); 
                // the rest is then
                strCategory = strCategory.Substring(iEnd, strCategory.Length - iEnd); 

            }

            Tracing.TraceMsg("Category found: " + strCategory + " - scheme: " + scheme); 

            this.category = new AtomCategory(strCategory, scheme);
        }


        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public AtomCategory Category</summary> 
        /// <returns></returns>
        //////////////////////////////////////////////////////////////////////
        public AtomCategory Category
        {
            get {return this.category;}
            set {this.category = value;}
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public QueryCategoryOperator Operator</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public QueryCategoryOperator Operator
        {
            get {return this.categoryOperator;}
            set {this.categoryOperator = value;}
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public bool Excluded</summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public bool Excluded
        {
            get {return this.isExcluded;}
            set {this.isExcluded = value;}
        }
        /////////////////////////////////////////////////////////////////////////////


    }

    //////////////////////////////////////////////////////////////////////
    /// <summary>Base class to create a GData query URI. Provides public 
    /// properties that describe the different aspects of the URI
    /// as well as a composite URI.
    /// </summary> 
    //////////////////////////////////////////////////////////////////////
    public class FeedQuery
    {
        #region member variables
        /// <summary>baseUri property holder</summary> 
        private string query;
        /// <summary>category part as string, comma seperated</summary> 
        private QueryCategoryCollection categories;
        /// <summary>author part as string</summary> 
        private string author;
        /// <summary>extra parameters as string</summary> 
        private string extraParameters;
        /// <summary>mininum date/time as DateTime</summary> 
        private DateTime datetimeMin;
        /// <summary>maximum date/time as DateTime</summary> 
        private DateTime datetimeMax;
        /// <summary>mininum date/time for the publicationdate as DateTime</summary> 
        private DateTime publishedMin;
        /// <summary>maximum date/time for the publicationdate as DateTime</summary> 
        private DateTime publishedMax;
        /// <summary>start-index as integer</summary> 
        private int startIndex;
        /// <summary>number of entries to retrieve as integer</summary> 
        private int numToRetrieve;
        /// <summary>alternative format as AlternativeFormat</summary> 
        private AlternativeFormat altFormat;
        /// <summary>the base URI</summary> 
        private string baseUri;
       
        #endregion
        //////////////////////////////////////////////////////////////////////
        /// <summary>Default constructor.</summary> 
        //////////////////////////////////////////////////////////////////////
        public FeedQuery()
        {
            // set some defaults...
            this.FeedFormat = AlternativeFormat.Atom;
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>public static DateTime EmptyDate</summary> 
        //////////////////////////////////////////////////////////////////////
        public static DateTime EmptyDate
        {
            get {
                // that's the blank value you get when setting a DateTime to an empty string inthe property browswer
                return new DateTime(1,1,1);
            }

        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>We do not hold on to the precalculated Uri.
        /// It's safer and cheaper to calculate this on the fly.
        /// Setting this loses the base Uri.</summary> 
        /// <returns>returns the complete UriPart that is used to execute the query</returns>
        //////////////////////////////////////////////////////////////////////
        public Uri Uri
        {
            get {
                return new Uri(this.baseUri + CalculateQuery());
                }
            set 
                {
                ParseUri(value);
                }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>Passing in a complete URI, we strip all the
        /// GData query-related things and then treat the rest
        /// as the base URI. For this we create a service.</summary> 
        /// <param name="uri">a complete URI</param>
        /// <param name="service">the new GData service for this URI</param>
        /// <param name="query">the parsed query object for this URI</param>
        //////////////////////////////////////////////////////////////////////
        public static void Parse(Uri uri, out Service service, out FeedQuery query)
        {
            query = new FeedQuery();

            query.ParseUri(uri);

            service = new Service();
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public string Query.</summary> 
        /// <returns>returns the query string portion of the URI</returns>
        //////////////////////////////////////////////////////////////////////
        public string Query
        {
            get {return this.query;}
            set {this.query = value; }
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public string Category.</summary> 
        /// <returns>the category filter</returns>
        //////////////////////////////////////////////////////////////////////
        public QueryCategoryCollection Categories
        {
            get {
                    if (this.categories == null)
                    {
                        this.categories = new QueryCategoryCollection(); 
                    }
                    return this.categories;
                }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public string ExtraParameters.</summary> 
        /// <returns></returns>
        //////////////////////////////////////////////////////////////////////
        public string ExtraParameters
        {
            get {return this.extraParameters;}
            set {this.extraParameters = value;}
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public string Author.</summary> 
        /// <returns>the requested author</returns>
        //////////////////////////////////////////////////////////////////////
        public string Author
        {
            get { return this.author;}
            set { this.author = value; }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>set's the mininum daterange value for the updated element</summary> 
        /// <returns>the min (inclusive) date/time</returns>
        //////////////////////////////////////////////////////////////////////
        public DateTime StartDate
        {
            get {return this.datetimeMin;}
            set {this.datetimeMin = value; }
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>set's the maximum daterange value for the updated element</summary> 
        /// <returns>the max (exclusive) date/time</returns>
        //////////////////////////////////////////////////////////////////////
        public DateTime EndDate
        {
            get {return this.datetimeMax;}
            set {this.datetimeMax = value; }
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>set's the mininum daterange value for the publication element</summary> 
        /// <returns>the min (inclusive) date/time</returns>
        //////////////////////////////////////////////////////////////////////
        public DateTime MinPublication
        {
            get {return this.publishedMin;}
            set {this.publishedMin = value; }
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>set's the maximum daterange value for the publication element</summary> 
        /// <returns>the max (exclusive) date/time</returns>
        //////////////////////////////////////////////////////////////////////
        public DateTime MaxPublication
        {
            get {return this.publishedMax;}
            set {this.publishedMax = value; }
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public int StartIndex.</summary> 
        /// <returns>the start-index query parameter, a 1-based index
        /// indicating the first result to be retrieved.</returns>
        //////////////////////////////////////////////////////////////////////
        public int StartIndex
        {
            get {return this.startIndex;}
            set {this.startIndex = value; }
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public int NumberToRetrieve.</summary> 
        /// <returns>the number of entries to retrieve</returns>
        //////////////////////////////////////////////////////////////////////
        public int NumberToRetrieve
        {
            get {return this.numToRetrieve;}
            set {this.numToRetrieve = value; }
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>Accessor method public AlternativeFormat FeedFormat.
        /// </summary> 
        /// <returns> </returns>
        //////////////////////////////////////////////////////////////////////
        public AlternativeFormat FeedFormat
        {
            get {return this.altFormat;}
            set {this.altFormat = value; }
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>protected void ParseUri</summary> 
        /// <param name="targetUri">takes an incoming Uri string and parses all the properties out of it</param>
        /// <returns>throws a query exception when it finds something wrong with the input, otherwise returns a baseuri</returns>
        //////////////////////////////////////////////////////////////////////
        protected virtual Uri ParseUri(Uri targetUri)
        {
            Reset(); 
            StringBuilder newPath = null;
            UriBuilder newUri = null; 

            if (targetUri != null)
            {
                TokenCollection tokens; 
                // want to check some basic things on this guy first...
                ValidateUri(targetUri);
                newPath = new StringBuilder("", 2048);  
                newUri = new UriBuilder(targetUri);
                newUri.Path = null; 
                newUri.Query = null; 

                // now parse the query string and take the properties out
                string [] parts = targetUri.Segments;
                bool fCategory = false;

                foreach (string part in parts)
                {
                    string segment = CleanPart(part);
                    if (segment.Equals("-") == true)
                    {
                        // found the category simulator
                        fCategory = true; 
                    }
                    else if (fCategory == true)
                    {
                        // take the string, and create some category objects out of it...
                        
                        // replace the curly braces and the or operator | so that we can tokenize better
                        segment = segment.Replace("%7B", "{"); 
                        segment = segment.Replace("%7D", "}");
                        segment = segment.Replace("%7C", "|");

                        // let's see if it's the only one...
                        tokens = new TokenCollection(segment, new char[1] {'|'}); 
                        QueryCategoryOperator op = QueryCategoryOperator.AND; 
                        foreach (String token in tokens)
                        {
                            // each one is a category
                            QueryCategory category = new QueryCategory(token, op); 
                            this.Categories.Add(category);
                            op = QueryCategoryOperator.OR; 
                        }
                    }
                    else
                    {
                        newPath.Append(part);
                    }
                }

                char [] deli = {'?','&'}; 

                tokens = new TokenCollection(targetUri.Query, deli); 
                foreach (String token in tokens )
                {
                    if (token.Length > 0)
                    {
                        char [] otherDeli = {'='};
                        String [] parameters = token.Split(otherDeli,2); 
                        switch (parameters[0])
                        {
                            case "q":
                                this.Query = parameters[1];
                                break;
                            case "author":
                                this.Author = parameters[1];
                                break;
                            case "start-index":
                                this.StartIndex = int.Parse(parameters[1], CultureInfo.InvariantCulture);
                                break;
                            case "max-results":
                                this.NumberToRetrieve = int.Parse(parameters[1], CultureInfo.InvariantCulture);
                                break;
                            case "updated-min":
                                this.StartDate = DateTime.Parse(parameters[1], CultureInfo.InvariantCulture);
                                break;
                            case "updated-max":
                                this.EndDate = DateTime.Parse(parameters[1], CultureInfo.InvariantCulture);
                                break;
                            case "published-min":
                                this.MinPublication = DateTime.Parse(parameters[1], CultureInfo.InvariantCulture);
                                break;
                            case "published-max":
                                this.MaxPublication = DateTime.Parse(parameters[1], CultureInfo.InvariantCulture);
                                break;
                            default:
                                break;
                        }
                    }
                }
            }

            if (newPath != null)
            {
                if (newPath[newPath.Length-1] == '/')
                    newPath.Length = newPath.Length -1 ;

                newUri.Path = newPath.ToString(); 
                this.baseUri = newUri.Uri.AbsoluteUri;

            }
            return null; 
        }
        /////////////////////////////////////////////////////////////////////////////

        

        //////////////////////////////////////////////////////////////////////
        /// <summary>protected void ParseUri</summary> 
        /// <param name="target">takes an incoming string and parses all the properties out of it</param>
        /// <returns>throws a query exception when it finds something wrong with the input, otherwise returns a baseuri</returns>
        //////////////////////////////////////////////////////////////////////
        protected Uri ParseUri(string target)
        {
            Reset(); 
            if (target != null)
            {
                return ParseUri(new Uri(target));
            }
            return null; 
            
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>Takes an incoming URI segment and removes leading/trailing slashes.</summary> 
        /// <param name="part">the URI segment to clean</param>
        /// <returns>the cleaned string</returns>
        //////////////////////////////////////////////////////////////////////
        static internal string CleanPart(string part)
        {
            Tracing.Assert(part != null, "part should not be null");
            if (part == null)
            {
                throw new ArgumentNullException("part"); 
            }
            
            string cleaned = part.Trim();
            if (cleaned.EndsWith("/"))
            {
                cleaned = cleaned.Substring(0, cleaned.Length-1);
            }
            if (cleaned.StartsWith("/"))
            {
                cleaned = cleaned.Substring(1, cleaned.Length-1);
            }

            return cleaned;
        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>Checks to see if the URI is valid to be used for an Atom query.</summary> 
        /// <returns>Throws a client exception if not</returns>
        //////////////////////////////////////////////////////////////////////
        static protected void ValidateUri(Uri uriToTest)
        {
            Tracing.Assert(uriToTest != null, "uriToTest should not be null");
            if (uriToTest == null)
            {
                throw new ArgumentNullException("uriToTest"); 
            }

            if (uriToTest.Scheme == Uri.UriSchemeFile || uriToTest.Scheme == Uri.UriSchemeHttp  || uriToTest.Scheme == Uri.UriSchemeHttps)
            {
                return;
            }
            throw new ClientQueryException("Only HTTP/HTTPS 1.1 protocol is currently supported");
        }
        /////////////////////////////////////////////////////////////////////////////


        //////////////////////////////////////////////////////////////////////
        /// <summary>Resets object state to default, as if newly created.
        /// </summary> 
        //////////////////////////////////////////////////////////////////////
        protected virtual void Reset()
        {
            this.query = this.author = String.Empty; 
            this.categories = null; 
            this.datetimeMax = this.datetimeMin = FeedQuery.EmptyDate; 
            this.startIndex = this.numToRetrieve = 0; 
            this.altFormat = AlternativeFormat.Atom;
        }
        /////////////////////////////////////////////////////////////////////////////

        //////////////////////////////////////////////////////////////////////
        /// <summary>Creates the partial URI query string based on all set properties.</summary> 
        /// <returns> string => the query part of the URI</returns>
        //////////////////////////////////////////////////////////////////////
        protected virtual string CalculateQuery()
        {
            Tracing.TraceCall("creating target Uri");


            StringBuilder newPath = new StringBuilder("", 2048);  


            // now let's build up a big string and check if we have all the parts we need
            bool firstTime = true; 

            // categories come first 
            
            foreach (QueryCategory category in this.Categories )
            {
                string strCategory = Utilities.UriEncodeReserved(category.Category.UriString); 

                if (Utilities.IsPersistable(strCategory))
                {
                    if (firstTime == true)
                    {
                        newPath.Append("/-/"); 
                    }
                    else
                    {
                        switch (category.Operator)
                        {
                            case QueryCategoryOperator.AND:
                                // we get another AND, so it's a new path
                                newPath.Append("/");
                                break;
                            case QueryCategoryOperator.OR:
                                newPath.Append("|");
                                break;
                        }
                    }
    
                    firstTime = false; 
    
                    if (category.Excluded == true)
                    {
                        newPath.AppendFormat("-{0}", strCategory);
                    }
                    else
                    {
                        newPath.AppendFormat("{0}", strCategory);
                    }   
                }
                else
                {
                    throw new ClientQueryException("One of the categories could not be persisted to a string");
                }
            }

            char paramInsertion = '?';
            
            if (this.FeedFormat != AlternativeFormat.Atom)
            {
                newPath.Append(paramInsertion);
                newPath.AppendFormat("alt={0}", FormatToString(this.FeedFormat));
                paramInsertion = '&'; 
            }

            // just add all the other things, as they are available... 
            if (Utilities.IsPersistable(this.Query))
            {  
                newPath.Append(paramInsertion);
                newPath.AppendFormat("q={0}", Utilities.UriEncodeReserved(this.Query));
                paramInsertion = '&'; 
            }
            if (Utilities.IsPersistable(this.Author))
            {
                newPath.Append(paramInsertion);
                newPath.AppendFormat("author={0}", Utilities.UriEncodeReserved(this.Author)); 
                paramInsertion = '&'; 
            }
            if (this.StartDate != FeedQuery.EmptyDate)
            {
                newPath.Append(paramInsertion);
                newPath.AppendFormat("updated-min={0}", Utilities.UriEncodeReserved(Utilities.LocalDateTimeInUTC(this.StartDate)));
                paramInsertion = '&'; 
            }
            if (this.EndDate != FeedQuery.EmptyDate)
            {
                newPath.Append(paramInsertion);
                newPath.AppendFormat("updated-max={0:G}", Utilities.UriEncodeReserved(Utilities.LocalDateTimeInUTC(this.EndDate)));
                paramInsertion = '&'; 
            }

            if (this.MinPublication != FeedQuery.EmptyDate)
            {
                newPath.Append(paramInsertion);
                newPath.AppendFormat("published-min={0:G}", Utilities.UriEncodeReserved(Utilities.LocalDateTimeInUTC(this.MinPublication)));
                paramInsertion = '&'; 
            }
            if (this.MaxPublication != FeedQuery.EmptyDate)
            {
                newPath.Append(paramInsertion);
                newPath.AppendFormat("published-max={0:G}", Utilities.UriEncodeReserved(Utilities.LocalDateTimeInUTC(this.MaxPublication)));
                paramInsertion = '&'; 
            }

            if (this.StartIndex != 0)
            {
                newPath.Append(paramInsertion);
                newPath.AppendFormat("start-index={0:d}", this.StartIndex);
                paramInsertion = '&'; 
            }
            if (this.NumberToRetrieve != 0)
            {
                newPath.Append(paramInsertion);
                newPath.AppendFormat("max-results={0:d}", this.NumberToRetrieve);
                paramInsertion = '&'; 
            }

            if (Utilities.IsPersistable(this.ExtraParameters))
            {
                newPath.Append(paramInsertion);
                newPath.Append(ExtraParameters);
            }

            return newPath.ToString();

        }
        /////////////////////////////////////////////////////////////////////////////



        //////////////////////////////////////////////////////////////////////
        /// <summary>Converts an AlternativeFormat to a string for use in
        /// the query string.</summary> 
        /// <param name="format">the format that we want to be converted to string </param>
        /// <returns>string version of the format</returns>
        //////////////////////////////////////////////////////////////////////
        static protected string FormatToString(AlternativeFormat format)
        {
            switch (format)
            {
                case AlternativeFormat.Atom:
                    return "atom";
                case AlternativeFormat.Rss:
                    return "rss";
                case AlternativeFormat.OpenSearchRss:
                    return "osrss";
            }
            return null;
        }
        /////////////////////////////////////////////////////////////////////////////
    }
    /////////////////////////////////////////////////////////////////////////////
    
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.